[update] 一般更新

This commit is contained in:
msincenselee 2022-01-25 16:09:20 +08:00
parent e260c16795
commit 7104a2fe0b
7 changed files with 53 additions and 18 deletions

View File

@ -63,6 +63,7 @@ class AlgoEngine(BaseEngine):
from .algos.dma_algo import DmaAlgo from .algos.dma_algo import DmaAlgo
from .algos.arbitrage_algo import ArbitrageAlgo from .algos.arbitrage_algo import ArbitrageAlgo
from .algos.spread_algo_v2 import SpreadAlgoV2 from .algos.spread_algo_v2 import SpreadAlgoV2
from .algos.autostopwin_algo import AutoStopWinAlgo
self.add_algo_template(TwapAlgo) self.add_algo_template(TwapAlgo)
self.add_algo_template(IcebergAlgo) self.add_algo_template(IcebergAlgo)
@ -73,6 +74,7 @@ class AlgoEngine(BaseEngine):
self.add_algo_template(DmaAlgo) self.add_algo_template(DmaAlgo)
self.add_algo_template(ArbitrageAlgo) self.add_algo_template(ArbitrageAlgo)
self.add_algo_template(SpreadAlgoV2) self.add_algo_template(SpreadAlgoV2)
self.add_algo_template(AutoStopWinAlgo)
def add_algo_template(self, template: AlgoTemplate): def add_algo_template(self, template: AlgoTemplate):
"""""" """"""
@ -180,7 +182,8 @@ class AlgoEngine(BaseEngine):
def stop_all(self): def stop_all(self):
"""""" """"""
for algo_name in list(self.algos.keys()): for algo_name in list(self.algos.keys()):
self.stop_algo(algo_name) if self.stop_algo(algo_name):
self.main_engine.write_log(f'{algo_name}已停止')
def subscribe(self, algo: AlgoTemplate, vt_symbol: str): def subscribe(self, algo: AlgoTemplate, vt_symbol: str):
"""""" """"""
@ -215,7 +218,7 @@ class AlgoEngine(BaseEngine):
contract = self.main_engine.get_contract(vt_symbol) contract = self.main_engine.get_contract(vt_symbol)
if not contract: if not contract:
self.write_log(f'委托下单失败,找不到合约:{vt_symbol}', algo_name=algo.algo_name) self.write_log(f'委托下单失败,找不到合约:{vt_symbol}', algo_name=algo.algo_name)
return return []
volume = round_to(volume, contract.min_volume) volume = round_to(volume, contract.min_volume)
if not volume: if not volume:

View File

@ -104,12 +104,10 @@ STOP_STATUS_MAP = {
# 假期后续可以从cta_option_config.json文件中获取更新 # 假期后续可以从cta_option_config.json文件中获取更新
holiday_dict = { holiday_dict = {
# 放假第一天:放假最后一天 # 放假第一天:放假最后一天
"2000124": "20200130", "20220131": "20220206",
"20200501": "20200505", "20220430": "20220504",
"20201001": "20201008", "20221001": "20221007",
"20210211": "20210217", # updated by 黄健威 2022.01.07
"20210501": "20210505",
"20211001": "20211007",
} }

View File

@ -142,9 +142,9 @@ class BackTestingEngine(object):
self.holdings = {} # 多空持仓 self.holdings = {} # 多空持仓
# 当前最新数据,用于模拟成交用
self.gateway_name = u'BackTest' self.gateway_name = u'BackTest'
# 当前最新数据,用于模拟成交用
self.last_bar = {} # 最新的bar self.last_bar = {} # 最新的bar
self.last_tick = {} # 最新tick self.last_tick = {} # 最新tick
self.last_dt = None # 最新时间 self.last_dt = None # 最新时间
@ -158,7 +158,7 @@ class BackTestingEngine(object):
# 回测计算相关 # 回测计算相关
self.use_margin = True # 使用保证金模式(期货使用,计算保证金时,按照开仓价计算。股票是按照当前价计算) self.use_margin = True # 使用保证金模式(期货使用,计算保证金时,按照开仓价计算。股票是按照当前价计算)
self.force_cross = False # 强制撮合成功,不使用价格比对,一般用于模拟市价成交
self.init_capital = 1000000 # 期初资金 self.init_capital = 1000000 # 期初资金
self.cur_capital = self.init_capital # 当前资金净值 self.cur_capital = self.init_capital # 当前资金净值
self.net_capital = self.init_capital # 实时资金净值每日根据capital和持仓浮盈计算 self.net_capital = self.init_capital # 实时资金净值每日根据capital和持仓浮盈计算
@ -604,6 +604,11 @@ class BackTestingEngine(object):
# 缺省使用保证金方式。(期货使用保证金/股票不使用保证金) # 缺省使用保证金方式。(期货使用保证金/股票不使用保证金)
self.use_margin = test_setting.get('use_margin', True) self.use_margin = test_setting.get('use_margin', True)
if 'force_cross' in test_setting:
self.force_cross = test_setting.get('force_cross', False)
if self.force_cross:
self.write_log(f'使用强制撮合模式!')
# 设置最大资金使用比例 # 设置最大资金使用比例
if 'percent_limit' in test_setting: if 'percent_limit' in test_setting:
self.write_log(u'设置最大资金使用比例:{}%'.format(test_setting.get('percent_limit'))) self.write_log(u'设置最大资金使用比例:{}%'.format(test_setting.get('percent_limit')))
@ -645,6 +650,7 @@ class BackTestingEngine(object):
# 创建资金K线 # 创建资金K线
self.create_fund_kline(self.test_name, use_renko=test_setting.get('use_renko', False)) self.create_fund_kline(self.test_name, use_renko=test_setting.get('use_renko', False))
# 自动输出日线净值曲线图png文件
self.is_plot_daily = test_setting.get('is_plot_daily', False) self.is_plot_daily = test_setting.get('is_plot_daily', False)
# 加载所有本地策略class # 加载所有本地策略class
@ -1293,8 +1299,8 @@ class BackTestingEngine(object):
sell_best_cross_price = tick.last_price sell_best_cross_price = tick.last_price
# 判断是否会成交 # 判断是否会成交
buy_cross = order.direction == Direction.LONG and order.price >= buy_cross_price buy_cross = order.direction == Direction.LONG and (order.price >= buy_cross_price or self.force_cross)
sell_cross = order.direction == Direction.SHORT and order.price <= sell_cross_price sell_cross = order.direction == Direction.SHORT and (order.price <= sell_cross_price or self.force_cross)
# 如果发生了成交 # 如果发生了成交
if buy_cross or sell_cross: if buy_cross or sell_cross:
@ -1321,9 +1327,9 @@ class BackTestingEngine(object):
# 2. 假设在上一根K线结束(也是当前K线开始)的时刻策略发出的委托为限价105 # 2. 假设在上一根K线结束(也是当前K线开始)的时刻策略发出的委托为限价105
# 3. 则在实际中的成交价会是100而不是105因为委托发出时市场的最优价格是100 # 3. 则在实际中的成交价会是100而不是105因为委托发出时市场的最优价格是100
if buy_cross: if buy_cross:
trade_price = min(order.price, buy_best_cross_price) trade_price = min(order.price, buy_best_cross_price) if not self.force_cross else order.price
else: else:
trade_price = max(order.price, sell_best_cross_price) trade_price = max(order.price, sell_best_cross_price) if not self.force_cross else order.price
# renko bar较为特殊使用委托价进行成交 # renko bar较为特殊使用委托价进行成交
if trade.vt_symbol.startswith('future_renko'): if trade.vt_symbol.startswith('future_renko'):

View File

@ -160,6 +160,12 @@ class PortfolioTestingEngine(BackTestingEngine):
self.use_pkb2 = test_setting.get('use_pkb2', True) self.use_pkb2 = test_setting.get('use_pkb2', True)
if self.use_tq: if self.use_tq:
self.use_pkb2 = False self.use_pkb2 = False
self.output(f'使用天勤数据')
if self.use_pkb2:
self.output(f'使用pkb2压缩格式')
else:
self.output(f'使用csv文件格式')
def prepare_data(self, data_dict): def prepare_data(self, data_dict):
""" """
@ -282,6 +288,7 @@ class PortfolioTestingEngine(BackTestingEngine):
bar.low_time = bar_data.get('low_time', None) # 最后一次进入低位区域的时间 bar.low_time = bar_data.get('low_time', None) # 最后一次进入低位区域的时间
bar.high_time = bar_data.get('high_time', None) # 最后一次进入高位区域的时间 bar.high_time = bar_data.get('high_time', None) # 最后一次进入高位区域的时间
else: else:
# 读取的bar是以bar结束时间作为datetimevnpy是以bar开始时间作为bar datetime
bar_datetime = dt - timedelta(seconds=self.bar_interval_seconds) bar_datetime = dt - timedelta(seconds=self.bar_interval_seconds)
bar = BarData( bar = BarData(
@ -400,7 +407,7 @@ class PortfolioTestingEngine(BackTestingEngine):
return None return None
df = pd.read_csv(file_path, encoding='gbk', parse_dates=False) df = pd.read_csv(file_path, encoding='gbk', parse_dates=False)
df.columns = ['date', 'time', 'last_price', 'volume', 'last_volume', 'open_interest', df.columns = ['date', 'time', 'last_price', 'last_volume', 'volume', 'open_interest',
'bid_price_1', 'bid_volume_1', 'bid_price_2', 'bid_volume_2', 'bid_price_3', 'bid_volume_3', 'bid_price_1', 'bid_volume_1', 'bid_price_2', 'bid_volume_2', 'bid_price_3', 'bid_volume_3',
'ask_price_1', 'ask_volume_1', 'ask_price_2', 'ask_volume_2', 'ask_price_3', 'ask_volume_3', 'BS'] 'ask_price_1', 'ask_volume_1', 'ask_price_2', 'ask_volume_2', 'ask_price_3', 'ask_volume_3', 'BS']

View File

@ -323,7 +323,7 @@ class SpreadTestingEngine(BackTestingEngine):
symbol, exchange = extract_vt_symbol(vt_symbol) symbol, exchange = extract_vt_symbol(vt_symbol)
underly_symbol = get_underlying_symbol(symbol) underly_symbol = get_underlying_symbol(symbol)
exchange_folder = VN_EXCHANGE_TICKFOLDER_MAP.get(exchange.value) exchange_folder = VN_EXCHANGE_TICKFOLDER_MAP.get(exchange.value,'LOCAL')
if exchange == Exchange.INE: if exchange == Exchange.INE:
file_path = os.path.abspath( file_path = os.path.abspath(

View File

@ -627,6 +627,16 @@ def check_chan_xt_nine_bi(kline, bi_list: List[ChanObject]):
if bi_9.high > gg > zg > bi_9.low > zd: if bi_9.high > gg > zg > bi_9.low > zd:
return ChanSignals.Q2L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二买', v2='九笔') return ChanSignals.Q2L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二买', v2='九笔')
if min_low == bi_7.low and max_high == bi_1.high and bi_6.high < bi_2.low: # 前7笔构成向下类趋势
zd = max([x.low for x in [bi_5, bi_6]])
zg = min([x.high for x in [bi_4, bi_6]])
gg = max([x.high for x in [bi_4, bi_6]])
if zg > zd and bi_8.high > gg == bi_4.high : # 456构成中枢7离开中枢8反包且8的高点大于gg,4高 >6高点
atan = (bi_4.high - bi_6.high) / (bi_5.bars + bi_6.bars - 1)
p = bi_6.high - atan * (bi_7.bars + bi_8.bars + bi_9.bars - 2)
if zd > bi_9.low > p:
return ChanSignals.Q2L0.value
elif direction == 1: elif direction == 1:
# 倒9笔是最高点倒一笔是最低点 # 倒9笔是最高点倒一笔是最低点
@ -688,8 +698,8 @@ def check_chan_xt_nine_bi(kline, bi_list: List[ChanObject]):
# 参考双重顶或者圆弧顶, 在 bi_5.low => bi_7.low => p点 形成一条斜线如果bi_9.high 在斜线之下,就是三卖 # 参考双重顶或者圆弧顶, 在 bi_5.low => bi_7.low => p点 形成一条斜线如果bi_9.high 在斜线之下,就是三卖
if dd == bi_5.low and zd == bi_7.low: if dd == bi_5.low and zd == bi_7.low:
atan = (zd - dd) / (bi_5.bars + bi_6.bars) atan = (zd - dd) / (bi_5.bars + bi_6.bars - 1)
p = bi_7.low + atan * (bi_7.bars + bi_8.bars + bi_9.bars) p = bi_7.low + atan * (bi_7.bars + bi_8.bars + bi_9.bars - 2)
if bi_9.high < p: if bi_9.high < p:
return ChanSignals.Q3S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类三卖', v2='九笔ZD三卖') return ChanSignals.Q3S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类三卖', v2='九笔ZD三卖')
@ -697,6 +707,16 @@ def check_chan_xt_nine_bi(kline, bi_list: List[ChanObject]):
if dd < zd <= bi_9.high < zg: if dd < zd <= bi_9.high < zg:
return ChanSignals.Q2S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二卖', v2='九笔') return ChanSignals.Q2S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二卖', v2='九笔')
if min_low == bi_1.low and max_high == bi_7.high and bi_2.high < bi_6.low: # 前7笔形成上涨趋势
zd = max([x.low for x in [bi_4, bi_6]])
zg = min([x.high for x in [bi_4, bi_6]])
dd = min([x.low for x in [bi_4, bi_6]])
if zg > zd and bi_8.low < dd == bi_4.low: # 456构成中枢7离开中枢8反包且8的低点小于dd,4低点< 6低点
atan = (bi_6.low - bi_4.low) / (bi_5.bars + bi_6.bars -1)
p = bi_6.low + atan * (bi_7.bars + bi_8.bars + bi_9.bars - 2)
if zg < bi_9.high < p:
return ChanSignals.Q2S0.value
return v return v

View File

@ -337,6 +337,7 @@ class ContractData(BaseData):
option_underlying: str = "" # vt_symbol of underlying contract option_underlying: str = "" # vt_symbol of underlying contract
option_type: OptionType = None option_type: OptionType = None
option_expiry: datetime = None option_expiry: datetime = None
option_portfolio: str = ""
option_index: str = "" # vt_symbol mapping cur option option_index: str = "" # vt_symbol mapping cur option
def __post_init__(self): def __post_init__(self):