Skip to content

Commit

Permalink
customized future info
Browse files Browse the repository at this point in the history
  • Loading branch information
Cuizi7 committed Dec 5, 2018
1 parent 1bb9a6e commit 50e2345
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 5 deletions.
2 changes: 1 addition & 1 deletion rqalpha/VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.2.0.39995e
3.2.0.dev.016e2e
3 changes: 2 additions & 1 deletion rqalpha/api/api_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
from rqalpha.model.instrument import Instrument, SectorCode as sector_code, IndustryCode as industry_code
# noinspection PyUnresolvedReferences
from rqalpha.const import (EXECUTION_PHASE, EXC_TYPE, ORDER_STATUS, SIDE, POSITION_EFFECT, ORDER_TYPE, MATCHING_TYPE,
RUN_TYPE, POSITION_DIRECTION)
RUN_TYPE, POSITION_DIRECTION, COMMISSION_TYPE)
# noinspection PyUnresolvedReferences
from rqalpha.model.order import Order, MarketOrder, LimitOrder, OrderStyle
# noinspection PyUnresolvedReferences
Expand All @@ -65,6 +65,7 @@
'ORDER_TYPE',
'RUN_TYPE',
'MATCHING_TYPE',
'COMMISSION_TYPE',
'EVENT',
]

Expand Down
2 changes: 2 additions & 0 deletions rqalpha/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ base:
init_positions: {}
# 根据价格最小变动单位调整发单价格
round_price: false
# 用户自定义的期货合约数据,用于设置期货手续菲费率
future_info: {}


extra:
Expand Down
9 changes: 9 additions & 0 deletions rqalpha/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from rqalpha.core.strategy_universe import StrategyUniverse
from rqalpha.core.global_var import GlobalVars
from rqalpha.core.strategy_context import StrategyContext
from rqalpha.data import future_info_cn
from rqalpha.data.base_data_source import BaseDataSource
from rqalpha.data.data_proxy import DataProxy
from rqalpha.environment import Environment
Expand All @@ -53,6 +54,7 @@
from rqalpha.utils.scheduler import Scheduler
from rqalpha.utils.config import set_locale
from rqalpha.utils.logger import system_log, basic_system_log, user_system_log, user_detail_log
from rqalpha.utils.dict_func import deep_update


jsonpickle_numpy.register_handlers()
Expand Down Expand Up @@ -163,6 +165,13 @@ def run(config, source_code=None, user_funcs=None):
mod_handler.set_env(env)
mod_handler.start_up()

try:
future_info = config.base.future_info
except AttributeError:
pass
else:
deep_update(future_info, future_info_cn.CN_FUTURE_INFO)

if not env.data_source:
env.set_data_source(BaseDataSource(config.base.data_bundle_path))
env.set_data_proxy(DataProxy(env.data_source))
Expand Down
28 changes: 27 additions & 1 deletion rqalpha/utils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import simplejson as json
import six

from rqalpha.const import RUN_TYPE, PERSIST_MODE, MARKET
from rqalpha.const import RUN_TYPE, PERSIST_MODE, MARKET, COMMISSION_TYPE
from rqalpha.utils import RqAttrDict, logger
from rqalpha.utils.i18n import gettext as _, localization
from rqalpha.utils.dict_func import deep_update
Expand Down Expand Up @@ -187,6 +187,7 @@ def _to_date(v):
config.base.init_positions = parse_init_positions(config.base.init_positions)
config.base.persist_mode = parse_persist_mode(config.base.persist_mode)
config.base.market = parse_market(config.base.market)
config.base.future_info = parse_future_info(config.base.future_info)

if config.extra.context_vars:
if isinstance(config.extra.context_vars, six.string_types):
Expand All @@ -198,6 +199,31 @@ def _to_date(v):
return config


def parse_future_info(future_info):
new_info = {}

for underlying_symbol, info in six.iteritems(future_info):
try:
underlying_symbol = underlying_symbol.upper()
except AttributeError:
raise RuntimeError(_("Invalid future info: underlying_symbol {] is illegal.".format(underlying_symbol)))

for field, value in six.iteritems(info):
if field in (
"open_commission_ratio", "close_commission_ratio", "close_commission_today_ratio"
):
new_info.setdefault(underlying_symbol, {})[field] = float(value)
elif field == "commission_type":
if not isinstance(value, COMMISSION_TYPE):
raise RuntimeError(_(
"Invalid future info: commission_type must be an instance of COMMISSION_TYPE Enum"
))
new_info.setdefault(underlying_symbol, {})[field] = value
else:
raise RuntimeError(_("Invalid future info: field {} is not valid".format(field)))
return new_info


def parse_accounts(accounts):
a = {}
if isinstance(accounts, tuple):
Expand Down
4 changes: 2 additions & 2 deletions tests/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
from .test_api_base import test_strategies as test_api_base_strategies
from .test_api_stock import test_strategies as test_api_stock_strategies
from .test_api_future import test_strategies as test_api_future_strategies
from .test_config import test_strategies as test_config_strategies

test_strategies = test_api_base_strategies + test_api_stock_strategies + test_api_future_strategies

test_strategies = test_api_base_strategies + test_api_stock_strategies + test_api_future_strategies + test_config_strategies

__all__ = [
"test_strategies"
Expand Down
83 changes: 83 additions & 0 deletions tests/api/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env python
# -*- 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.api import *

from ..utils import make_test_strategy_decorator

test_strategies = []

as_test_strategy = make_test_strategy_decorator({
"base": {
"start_date": "2018-04-01",
"end_date": "2018-05-01",
"frequency": "1d",
"accounts": {
"future": 10000000000
}
},
"extra": {
"log_level": "error",
},
"mod": {
"sys_progress": {
"enabled": True,
"show": True,
},
},
}, test_strategies)


def assert_almost_equal(first, second):
assert round(abs(first - second), 10) == 0


@as_test_strategy({
"base": {
"future_info": {
"SC": {
"close_commission_ratio": 0.0001,
"open_commission_ratio": 0.0002,
"commission_type": COMMISSION_TYPE.BY_MONEY,
}
}
}
})
def test_future_info():
def init(context):
context.f1 = "SC1809"
subscribe_event(EVENT.TRADE, on_trade)

def handle_bar(*_):
buy_open("SC1809", 2)
sell_close("SC1809", 2, close_today=False)

def on_trade(event):
trade = event.trade
contract_multiplier = instruments("SC1809").contract_multiplier
if trade.position_effect == POSITION_EFFECT.OPEN:
assert_almost_equal(
trade.transaction_cost, 0.0002 * trade.last_quantity * trade.last_price * contract_multiplier
)
elif trade.position_effect == POSITION_EFFECT.CLOSE:
assert_almost_equal(
trade.transaction_cost, 0.0001 * trade.last_quantity * trade.last_price * contract_multiplier
)
else:
assert trade.transaction_cost == 0

return init, handle_bar

0 comments on commit 50e2345

Please sign in to comment.