Skip to content

Commit

Permalink
benchmark_portfolio support old properties for compatible
Browse files Browse the repository at this point in the history
  • Loading branch information
Cuizi7 committed Dec 2, 2018
1 parent 05aa103 commit 7f1217c
Show file tree
Hide file tree
Showing 24 changed files with 189 additions and 90 deletions.
5 changes: 3 additions & 2 deletions rqalpha/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def __init__(self, config):
self.event_bus = EventBus()
self.portfolio = None
self.booking = None
self.benchmark_provider = None
self.benchmark_portfolio = None
self.calendar_dt = None
self.trading_dt = None
Expand Down Expand Up @@ -200,5 +201,5 @@ def get_trade_commission(self, account_type, trade):
def get_order_transaction_cost(self, account_type, order):
return self._get_transaction_cost_decider(account_type).get_order_transaction_cost(order)

def set_benchmark_portfolio(self, benchmark_portfolio):
self.benchmark_portfolio = benchmark_portfolio
def set_benchmark_provider(self, benchmark_provider):
self.benchmark_provider = benchmark_provider
10 changes: 9 additions & 1 deletion rqalpha/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ def get_order_transaction_cost(self, order):
raise NotImplementedError


class AbstractBenchmarkPortfolio(with_metaclass(abc.ABCMeta)):
class AbstractBenchmarkProvider(with_metaclass(abc.ABCMeta)):
"""
基准组合模块,通过实现该接口可以定义基准组合的实现逻辑,基准组合的收益率将被用于画图及策略分析
"""
Expand All @@ -686,3 +686,11 @@ def daily_returns(self):
"""
raise NotImplementedError

@property
@abc.abstractmethod
def total_returns(self):
"""
[float] 累计收益率
"""
raise NotImplementedError

4 changes: 4 additions & 0 deletions rqalpha/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
from rqalpha.interface import Persistable
from rqalpha.mod import ModHandler
from rqalpha.model.bar import BarMap
from rqalpha.model.benchmark_portfolio import BenchmarkPortfolio
from rqalpha.const import RUN_TYPE
from rqalpha.utils import create_custom_exception, run_with_user_log_disabled, scheduler as mod_scheduler
from rqalpha.utils.exception import CustomException, is_user_exc, patch_user_exc
Expand Down Expand Up @@ -211,6 +212,9 @@ def run(config, source_code=None, user_funcs=None):
env.portfolio = broker.get_portfolio()
except NotImplementedError:
pass
else:
if env.benchmark_provider:
env.benchmark_portfolio = BenchmarkPortfolio(env.benchmark_provider, env.portfolio.units)

try:
env.booking = broker.get_booking()
Expand Down
43 changes: 0 additions & 43 deletions rqalpha/mod/rqalpha_mod_sys_benchmark/benchmark_portfolio.py

This file was deleted.

65 changes: 65 additions & 0 deletions rqalpha/mod/rqalpha_mod_sys_benchmark/benchmark_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
#
# Copyright 2017 Ricequant, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np

from rqalpha.interface import AbstractBenchmarkProvider
from rqalpha.environment import Environment
from rqalpha.events import EVENT
from rqalpha.utils.i18n import gettext as _


class BackTestPriceSeriesBenchmarkProvider(AbstractBenchmarkProvider):
def __init__(self, order_book_id):
self._order_book_id = order_book_id
self._daily_return_series = None
self._total_return_series = None
self._index = 0

event_bus = Environment.get_instance().event_bus
event_bus.add_listener(EVENT.POST_SYSTEM_INIT, self._on_system_init)
event_bus.prepend_listener(EVENT.AFTER_TRADING, self._on_after_trading)

def _on_system_init(self, _):
env = Environment.get_instance()
bar_count = len(env.config.base.trading_calendar) + 1
end_date = env.config.base.end_date
close_series = env.data_proxy.history_bars(
self._order_book_id, bar_count, "1d", "close", end_date, skip_suspended=False, adjust_type='pre'
)
if len(close_series) < bar_count:
raise RuntimeError(_("Valid benchmark: unable to load enough close price."))

self._total_return_series = (close_series - close_series[0]) / close_series[0]

self._daily_return_series = np.zeros((bar_count, ))
self._daily_return_series[1:] = (close_series[1:] - close_series[:-1]) / close_series[:-1]

def _on_after_trading(self, _):
self._index += 1

@property
def daily_returns(self):
return self._daily_return_series[self._index]

@property
def total_returns(self):
return self._total_return_series[self._index]


class RealTimePriceSeriesBenchmarkProvider(AbstractBenchmarkProvider):
def __init__(self, order_book_id):
self._order_book_id = order_book_id
14 changes: 6 additions & 8 deletions rqalpha/mod/rqalpha_mod_sys_benchmark/mod.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
from rqalpha.utils.logger import system_log
from rqalpha.const import RUN_TYPE

from .benchmark_portfolio import BackTestPriceSeriesBenchmarkPortfolio, RealTimePriceSeriesBenchmarkPortfolio


class BenchmarkMod(AbstractMod):
def start_up(self, env, mod_config):
Expand All @@ -35,12 +33,12 @@ def start_up(self, env, mod_config):
system_log.info("No order_book_id set, BenchmarkMod disabled.")
return

benchmark_portfolio = BackTestPriceSeriesBenchmarkPortfolio(
order_book_id
) if env.config.base.run_type == RUN_TYPE.BACKTEST else RealTimePriceSeriesBenchmarkPortfolio(
order_book_id
)
env.set_benchmark_portfolio(benchmark_portfolio)
if env.config.base.run_type == RUN_TYPE.BACKTEST:
from .benchmark_provider import BackTestPriceSeriesBenchmarkProvider as BTProvider
env.set_benchmark_provider(BTProvider(order_book_id))
else:
from .benchmark_provider import RealTimePriceSeriesBenchmarkProvider as RTProvider
env.set_benchmark_portfolio(RTProvider(order_book_id))

def tear_down(self, code, exception=None):
pass
12 changes: 6 additions & 6 deletions rqalpha/mod/rqalpha_mod_sys_benchmark/testing.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from rqalpha.utils.testing import DataProxyFixture


class BackTestPriceSeriesBenchmarkPortfolioFixture(DataProxyFixture):
class BackTestPriceSeriesBenchmarkProviderFixture(DataProxyFixture):
def __init__(self, *args, **kwargs):
super(BackTestPriceSeriesBenchmarkPortfolioFixture, self).__init__(*args, **kwargs)
super(BackTestPriceSeriesBenchmarkProviderFixture, self).__init__(*args, **kwargs)

self.benchmark_portfolio = None
self.benchmark_provider = None
self.benchmark_order_book_id = None

def init_fixture(self):
from rqalpha.mod.rqalpha_mod_sys_benchmark.benchmark_portfolio import BackTestPriceSeriesBenchmarkPortfolio
from rqalpha.mod.rqalpha_mod_sys_benchmark.benchmark_provider import BackTestPriceSeriesBenchmarkProvider

super(BackTestPriceSeriesBenchmarkPortfolioFixture, self).init_fixture()
self.benchmark_portfolio = BackTestPriceSeriesBenchmarkPortfolio(self.benchmark_order_book_id)
super(BackTestPriceSeriesBenchmarkProviderFixture, self).init_fixture()
self.benchmark_provider = BackTestPriceSeriesBenchmarkProvider(self.benchmark_order_book_id)
66 changes: 66 additions & 0 deletions rqalpha/model/benchmark_portfolio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
#
# Copyright 2017 Ricequant, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from rqalpha.environment import Environment
from rqalpha.const import DAYS_CNT


class BenchmarkPortfolio(object):
def __init__(self, benchmark_provider, units):
self._provider = benchmark_provider
self._units = units

@property
def units(self):
return self._units

@property
def daily_returns(self):
return self._provider.daily_returns

@property
def total_returns(self):
return self._provider.total_returns

@property
def annualized_returns(self):
# fixme: do not rely on env
if self.unit_net_value <= 0:
return -1

env = Environment.get_instance()
date_count = float(env.data_proxy.count_trading_dates(env.config.base.start_date, env.trading_dt.date()))
return self.unit_net_value ** (DAYS_CNT.TRADING_DAYS_A_YEAR / date_count) - 1

@property
def unit_net_value(self):
return 1 + self.total_returns

@property
def static_unit_net_value(self):
return self.unit_net_value / (1 + self.daily_returns)

@property
def total_value(self):
return self.units * self.unit_net_value

@property
def cash(self):
return 0

@property
def market_value(self):
return self.total_value
Binary file modified tests/outs/test_f_buy_and_hold.pkl
Binary file not shown.
Binary file modified tests/outs/test_f_macd.pkl
Binary file not shown.
Binary file modified tests/outs/test_f_macd_signal.pkl
Binary file not shown.
Binary file modified tests/outs/test_f_mean_reverting.pkl
Binary file not shown.
Binary file modified tests/outs/test_s_buy_and_hold.pkl
Binary file not shown.
Binary file modified tests/outs/test_s_dma.pkl
Binary file not shown.
Binary file modified tests/outs/test_s_dual_thrust.pkl
Binary file not shown.
Binary file modified tests/outs/test_s_golden_cross.pkl
Binary file not shown.
Binary file modified tests/outs/test_s_scheduler.pkl
Binary file not shown.
Binary file modified tests/outs/test_s_tick_size.pkl
Binary file not shown.
Binary file modified tests/outs/test_s_turtle.pkl
Binary file not shown.
Binary file modified tests/outs/test_s_turtle_signal.pkl
Binary file not shown.
Binary file modified tests/outs/test_sf_buy_and_hold.pkl
Binary file not shown.
2 changes: 0 additions & 2 deletions tests/outs/time.csv
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
date_time,time_spend
2018-06-13 10:46:12.018948,23.042125
2018-06-13 10:47:01.146415,23.110269

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from datetime import date

from rqalpha.utils.testing import RQAlphaTestCase
from rqalpha.mod.rqalpha_mod_sys_benchmark.testing import BackTestPriceSeriesBenchmarkProviderFixture
from rqalpha.events import EVENT, Event


class BackTestPriceSeriesBenchmarkProviderTestCase(BackTestPriceSeriesBenchmarkProviderFixture, RQAlphaTestCase):
def __init__(self, *args, **kwargs):
super(BackTestPriceSeriesBenchmarkProviderTestCase, self).__init__(*args, **kwargs)
self.benchmark_order_book_id = "000300.XSHG"
self.env_config["base"].update({
"start_date": date(2018, 9, 3), "end_date": date(2018, 9, 25)
})

def test_returns(self):
self.env.event_bus.publish_event(Event(EVENT.POST_SYSTEM_INIT))
self.assertEqual(self.benchmark_provider.daily_returns, 0)
self.env.event_bus.publish_event(Event(EVENT.AFTER_TRADING))
self.assertAlmostEqual(self.benchmark_provider.daily_returns, (3321.82 - 3334.50) / 3334.50)
self.assertAlmostEqual(self.benchmark_provider.total_returns, (3321.82 - 3334.50) / 3334.50)
for i in range(10):
self.env.event_bus.publish_event(Event(EVENT.AFTER_TRADING))
self.assertAlmostEqual(self.benchmark_provider.daily_returns, (3204.92 - 3242.09) / 3242.09)
self.assertAlmostEqual(self.benchmark_provider.total_returns, (3204.92 - 3334.50) / 3334.50)


if __name__ == "__main__":
import unittest
unittest.main()

0 comments on commit 7f1217c

Please sign in to comment.