Python 算法交易实验68 回测对象重构

2024-03-16 11:28

本文主要是介绍Python 算法交易实验68 回测对象重构,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

说明

从有这个想法,到勉强完工,整个过程还是持续了很长时间。主要原因有:

  • 1 去年12月没有遵守【原则】,手工乱下了一堆单子,然后满仓了。等这些单子“解冻”估计还要一阵子,所以也没有很急。
  • 2 在做的过程中,想做一些工具层面的升级,所以会花时间做一些依赖服务。

最后觉得还是要尽快完成一版,所以才想写本篇文章。
在这个版本中,不去考虑回撤、或者平均模型分的问题。

内容

1 样例数据

假设是分钟数据,但我想甚至是按天的数据可能也行。嗯,后续可以试一下天级别数据建模。有时候我也在想,是不是我一开始把问题搞的过于复杂了,分钟级别的判断是否需要?

言归正传,还是回到分钟级数据。未来,等到国内允许(非常简单的,普遍的那种)用接口进行交易,那么其实还是要用分钟级数据的。秒级的倒真没必要,又不搞高频。

# 排序好的
rec_data_list = [{'data_dt': '2013-03-15 09:31:00',
'open': 3.03,
'close': 2.9,
'high': 3.04,
'low': 2.8,
'decision_score':111
},
{'data_dt': '2013-03-15 09:32:00',
'open': 3.13,
'close': 3.0,
'high': 3.14,
'low': 2.9,
'decision_score':610}
,
{'data_dt': '2013-03-15 09:33:00',
'open': 3.13,
'close': 3.0,
'high': 3.14,
'low': 2.9,
'decision_score':300
},
{'data_dt': '2013-03-16 09:33:00',
'open': 3.13,
'close': 3.0,
'high': 3.14,
'low': 2.9,
'decision_score':300
},
{'data_dt': '2013-03-16 13:33:00',
'open': 3.13,
'close': 3.0,
'high': 3.14,
'low': 2.9,
'decision_score':601
},
{'data_dt': '2013-03-20 13:33:00',
'open': 3.13,
'close': 3.0,
'high': 3.14,
'low': 2.9,
'decision_score':601
},
{'data_dt': '2013-03-20 14:33:00',
'open': 3.13,
'close': 3.0,
'high': 3.14,
'low': 2.9,
'decision_score':601
},
{'data_dt': '2013-03-21 14:33:00',
'open': 3.13,
'close': 13.0,
'high': 3.14,
'low': 2.9,
'decision_score':601
},
{'data_dt': '2013-03-21 14:59:00',
'open': 3.13,
'close': 13.1,
'high': 3.14,
'low': 2.9,
'decision_score':610
},
{'data_dt': '2013-03-22 14:00:00',
'open': 3.13,
'close': 0.1,
'high': 3.14,
'low': 2.9,
'decision_score':610
}]rec_dt_list = ['2013-03-15 09:31:00','2013-03-15 09:32:00','2013-03-15 09:33:00',
'2013-03-16 09:33:00','2013-03-16 13:33:00','2013-03-20 13:33:00',
'2013-03-20 14:33:00','2013-03-21 14:33:00','2013-03-21 14:59:00',
'2013-03-22 14:00:00']

默认的策略参数,初始资本6000,每单金额5000,最大容许资产损失10%,最大持有天数为3。
买入的分值下限是600,卖出的分值上限是500。
费率设置为千5,订单的盈利终止是1个点,损失终止是2个点。

strategy_para = {
'init_cap': 6000,
'per_order_amt':5000,
'max_cap_loss_rate': -0.1,
'max_hold_order_num':1,
'max_order_hold_days':3,
'model_singal_score_buy':600,
'model_singal_score_sell':500,
'fee_rate': 0.005,
'etf_code': '510300',
'order_win_stop_rate':0.01,
'order_loss_stop_rate': -0.02
}

2 对象

对象依赖于两个服务:

  • 1 global_buffer: 这个服务提供了一个简单的访问redis变量的方法,提供set和get两种方法。一个核心的应用是访问/维护一个全局变量,限制在一段时间内可用的资金总量。这个服务未来可被更多的程序使用,提供全局缓存(元数据)。
  • 2 gfgo_lite: 这个服务提供了参数化的函数处理服务。在这里,用于计算时间间隔,例如订单的最长持久时间和最短禁止售卖时间。gfgo_lite的时间处理方式不同于time或者datetime这样的包,而是采用字典查询+偏移推算的方法,速度要快的多。而这个服务更大的作用在于确保global_func这个庞大而理想化的项目可以持续下去,最终实现完全的参数化调用函数以及弹性拓展算力的目的。再往后则是Agent相关的内容。

对象使用了transitions包的有限状态机模块,从而使各状态的变化更加清晰。虽然最后并不是理想的结果,但是也似乎可用。

另外本想在规则这块想写的高级点的,但是,就这样吧…

import copy
import requests as req 
import numpy as np 
import pandas as pd 
wan_ip ='****'class BackTest2:def __init__(self,name = None, global_buffer_ip = None, space_name = None):# 元数据 flip步需要基于数据,更新元数据  ~ update meta | dataself.meta = {}# 数据 flop步需要基于元数据,作出action ~ update data | metaself.data = {}# 行动,也就是变化self.action = None# 全局缓存ipself.global_buffer_ip = global_buffer_ipself.space_name  = space_nameself.close_orders = []# 接受策略参数,并进行初始化def _init_para(self, para_dict = None):'''初始资本 init_cap每笔交易金额(初始资本 > 每笔交易金额 * (1+资本回撤率)) per_order_amt最大资本亏损率 max_cap_loss_rate最大持有订单 max_hold_order_num最大订单持有(交易)时隙 max_order_hold_trade_slots订单买入模型分下限 model_singal_score_buy订单卖出模型分上限 model_singal_score_sell'''for x in ['init_cap', 'per_order_amt','max_cap_loss_rate','max_hold_order_num','max_order_hold_days','model_singal_score_buy','model_singal_score_sell','etf_code','order_win_stop_rate','order_loss_stop_rate' ] :self.meta[x] = para_dict[x]self.meta['cash'] = para_dict['init_cap']self.meta['hold'] = 0# 获取全局数据# BT2同时还需要收到全局参数的控制;这意味着若干BT2可以同时进行测试def _get_global_control_meta(self,global_buffer_ip = None, space_name = None,varname = None):# flipglobal_buffer_ip = global_buffer_ip or self.global_buffer_ipspace_name = space_name or self.space_namepara_dict  ={'space':space_name,'varname':varname,'ttl': 86400 # 可以不写,默认86400}return req.post('http://%s:24088/getx/' % global_buffer_ip,json = para_dict).json()def _set_global_control_meta(self,global_buffer_ip = None, space_name = None,varname = None, value = None,persist='yes'):# flipglobal_buffer_ip = global_buffer_ip or self.global_buffer_ipspace_name = space_name or self.space_namepara_dict  ={'space':space_name,'varname':varname,'value':value,'ttl': 86400, # 'persist':persist}return req.post('http://%s:24088/setx/' % global_buffer_ip,json = para_dict).json()def _get_time_gap(self,global_buffer_ip = None,start_dt = None, end_dt =None, time_unit = None,bias_hours = -8):global_buffer_ip = global_buffer_ip or self.global_buffer_ipsome_dict = {}some_dict['start_dt'] = start_dtsome_dict['end_dt'] = end_dtsome_dict['time_unit'] = time_unitsome_dict['bias_hours'] = bias_hoursres = req.post('http://%s:24090/time_gap/' % global_buffer_ip, json = some_dict).json()return res # 从外部获取数据def get_data(self,dt_list = None, rec_list = None):last_dt = self.meta.get('last_dt') or ''# 找到第一个大于 last_dt 的日期的索引pos = np.argwhere(np.array(dt_list) > last_dt)# 如果找到了满足条件的日期if len(pos) > 0:# 获取索引的第一个元素pos = pos[0][0]# 使用索引获取相应的日期和记录dt = dt_list[pos]rec = rec_list[pos]print("Date:", dt)print("Record:", rec)return  dt, recelse:print("No date found after", last_dt)return None # 买def _buy(self, price = None, dt = None):per_order_amt = self.meta['per_order_amt']stocks = int(per_order_amt /(100 * price)) * 100self.data['code'] = self.meta['etf_code']self.data['buy_price'] = price self.data['buy_dt'] = dt self.data['stocks'] = stocksself.data['buy_amt'] = price * stocksself.meta['cash'] = self.meta['cash'] - self.data['buy_amt'] self.meta['hold'] = self.data['buy_amt']# 改动全局总量monthly_quota = self._get_global_control_meta(varname='monthly_quota')monthly_quota -= self.data['buy_amt'] self._set_global_control_meta(varname='monthly_quota', value=monthly_quota)return True# 卖def _sell(self, price = None, dt = None, fee=0.005):self.data['sell_price'] = price self.data['sell_dt'] = dt self.data['sell_amt'] = price * self.data['stocks']self.data['gp'] = self.data['sell_amt'] - self.data['buy_amt']self.data['np'] = self.data['sell_amt'] * (1-fee) - self.data['buy_amt']self.data['npr'] = round(self.data['np']/self.data['buy_amt'],4)self.meta['cash'] = self.meta['cash'] + self.data['sell_amt'] * (1-fee)self.meta['hold'] = 0monthly_quota = self._get_global_control_meta(varname='monthly_quota')monthly_quota += self.data['buy_amt'] self._set_global_control_meta(varname='monthly_quota', value=monthly_quota)self.close_orders.append(copy.deepcopy(self.data))self.data = {}return True# 规则集将会直接更改元数据def ruleset(self, data = None):# input set : 收盘价,模型分,时间 |  init_cap , per_order_amt ,max_cap_loss_rate, max_hold_order_num ,max_order_hold_trade_slots , model_singal_score_buy , model_singal_score_sell# -9, close = data['close']dt = data['data_dt']decision_score = data['decision_score']cash = self.meta['cash']init_cap = self.meta['init_cap']model_singal_score_buy = self.meta['model_singal_score_buy']max_order_hold_days = self.meta['max_order_hold_days']model_singal_score_sell = self.meta['model_singal_score_sell']order_win_stop_rate = self.meta['order_win_stop_rate']order_loss_stop_rate = self.meta['order_loss_stop_rate']max_cap_loss_rate = self.meta['max_cap_loss_rate']per_order_amt = self.meta['per_order_amt']# 空仓if self.state == 'Init':the_event = 'unchange'self.trigger(the_event)return Trueif self.state.startswith('E'):# 如果收到全局控制,就不能再买入monthly_quota = self._get_global_control_meta(varname='monthly_quota')if monthly_quota < per_order_amt:self.trigger('unchange')return True# 判断买卖if decision_score >= model_singal_score_buy:the_event = 'buy'self._buy(price =close, dt = dt )else:the_event = 'unchange'self.trigger(the_event)return Trueif self.state.startswith('H'):hold_value = close * self.data['stocks']self.meta['hold'] = hold_valuecur_cap = cash + hold_valuerate = (cur_cap - init_cap)/init_capprint('rate: ',rate)# 判断涨跌if rate >=-0.03 and rate <0.03:if self.state in ['HL1','HL2']:the_event ='up'elif self.state in ['HW1','HW2']:the_event = 'down'else:the_event = 'unchange' elif rate >=-0.09 and rate <-0.03:if self.state in ['HB','HW1','HW2']:the_event  = 'down'elif self.state in ['HL2']:the_event = 'up'else:the_event = 'unchange' elif rate <-0.09:if self.state in ['HL1','HB','HW1','HW2']:the_event = 'down'else:the_event = 'unchange'elif rate >=0.03 and rate <0.09:if self. state in ['HL2','HL1','HB']:the_event = 'up'elif self.state in ['HW2']:the_event = 'down'else:the_event = 'unchange'else:if self.state in ['HL2','HL1','HB','HW1']:the_event = 'up'else:the_event = 'unchange'self.trigger(the_event)# 当资产损失超过阈值,会被停止if rate < max_cap_loss_rate:self._sell(price = close, dt =dt)self.trigger('stop')return True# 判断买卖## 时间限制buy_dt = self.data['buy_dt']time_gap = self._get_time_gap(start_dt =buy_dt ,end_dt =dt , time_unit ='hours')if time_gap < 8 :the_event = 'unchange'return True          else:if time_gap/24 >= max_order_hold_days:self._sell(price = close, dt =dt)self.trigger('sell')print('a')else:# 模型控制if decision_score < model_singal_score_sell:self._sell(price = close, dt =dt)self.trigger('sell')print('b')# 订单交易控制else:order_float_rev = (close - self.data['buy_price'])/self.data['buy_price']if order_float_rev >= order_win_stop_rate:self._sell(price = close, dt =dt)self.trigger('sell')print('c')elif order_float_rev < order_loss_stop_rate:self._sell(price = close, dt =dt)self.trigger('sell')print('d')else:self.trigger('unchange')return True                    # B是0+-3个点, W1是 6+-3个点,W2是大于9个点
# 11个状态
states = ['Init','EB','HB','HW1','HW2','EW1','EW2','HL1','HL2','EL1','EL2','Stop']
transitions = [# unchange事件{'trigger': 'unchange', 'source': 'Init', 'dest': 'EB'},{'trigger': 'unchange', 'source': 'EB', 'dest': 'EB'},{'trigger': 'unchange', 'source': 'HB', 'dest': 'HB'},{'trigger': 'unchange', 'source': 'HW1', 'dest': 'HW1'},{'trigger': 'unchange', 'source': 'HW2', 'dest': 'HW2'},{'trigger': 'unchange', 'source': 'EW1', 'dest': 'EW1'},{'trigger': 'unchange', 'source': 'EW2', 'dest': 'EW2'},{'trigger': 'unchange', 'source': 'HL1', 'dest': 'HL1'},{'trigger': 'unchange', 'source': 'HL2', 'dest': 'HL2'},{'trigger': 'unchange', 'source': 'EL1', 'dest': 'EL1'},{'trigger': 'unchange', 'source': 'EL2', 'dest': 'EL2'},# up事件:比上一个level高3个点, Init有一个InitCap,约定 B_center = InitCap,  B的Band定为3个点, B+3pt =  W1的下界以此类推{'trigger': 'up', 'source': 'Init', 'dest': 'EB'},# up对E无影响{'trigger': 'up', 'source': 'EB', 'dest': 'EB'},{'trigger': 'up', 'source': 'EW1', 'dest': 'EW1'},{'trigger': 'up', 'source': 'EW2', 'dest': 'EW2'},{'trigger': 'up', 'source': 'EL1', 'dest': 'EL1'},{'trigger': 'up', 'source': 'EL2', 'dest': 'EL2'},# up对H有影响{'trigger': 'up', 'source': 'HB', 'dest': 'HW1'},{'trigger': 'up', 'source': 'HW1', 'dest': 'HW2'},{'trigger': 'up', 'source': 'HW2', 'dest': 'Stop'},{'trigger': 'up', 'source': 'HL1', 'dest': 'HB'},{'trigger': 'up', 'source': 'HL2', 'dest': 'HL1'},    # down事件:类似up事件{'trigger': 'down', 'source': 'Init', 'dest': 'EB'},{'trigger': 'down', 'source': 'EB', 'dest': 'EB'},{'trigger': 'down', 'source': 'EW1', 'dest': 'EW1'},{'trigger': 'down', 'source': 'EW2', 'dest': 'EW2'},{'trigger': 'down', 'source': 'EL1', 'dest': 'EL1'},{'trigger': 'down', 'source': 'EL2', 'dest': 'EL2'},# down对H有影响{'trigger': 'down', 'source': 'HB', 'dest': 'HL1'},{'trigger': 'down', 'source': 'HW1', 'dest': 'HB'},{'trigger': 'down', 'source': 'HW2', 'dest': 'HW1'},{'trigger': 'down', 'source': 'HL1', 'dest': 'EL2'},{'trigger': 'down', 'source': 'HL2', 'dest': 'Stop'},    # buy事件,仅对E类生效{'trigger': 'buy', 'source': 'EB', 'dest': 'HB'},{'trigger': 'buy', 'source': 'EW1', 'dest': 'HW1'},{'trigger': 'buy', 'source': 'EW2', 'dest': 'HW2'},{'trigger': 'buy', 'source': 'EL1', 'dest': 'HL1'},{'trigger': 'buy', 'source': 'EL2', 'dest': 'HL2'},# sell事件,仅对H类生效{'trigger': 'sell', 'source': 'HB', 'dest': 'EB'},{'trigger': 'sell', 'source': 'HW1', 'dest': 'EW1'},{'trigger': 'sell', 'source': 'HW2', 'dest': 'EW2'},{'trigger': 'sell', 'source': 'HL1', 'dest': 'EL1'},{'trigger': 'sell', 'source': 'HL2', 'dest': 'EL2'}, # stop事件{'trigger': 'stop', 'source': 'Init', 'dest': 'Stop'},{'trigger': 'stop', 'source': 'HB', 'dest': 'Stop'}, {'trigger': 'stop', 'source': 'HL1', 'dest': 'Stop'},{'trigger': 'stop', 'source': 'HL2', 'dest': 'Stop'},{'trigger': 'stop', 'source': 'HW1', 'dest': 'Stop'},{'trigger': 'stop', 'source': 'HW2', 'dest': 'Stop'},{'trigger': 'stop', 'source': 'EB', 'dest': 'Stop'},{'trigger': 'stop', 'source': 'EL1', 'dest': 'Stop'},{'trigger': 'stop', 'source': 'EL2', 'dest': 'Stop'},{'trigger': 'stop', 'source': 'EW1', 'dest': 'Stop'},{'trigger': 'stop', 'source': 'EW2', 'dest': 'Stop'},# init事件{'trigger': 'init', 'source': 'Stop', 'dest': 'Init'},   
]

3 使用测试

先使用状态机对对象进行封装

from transitions import Machine
# 创建状态机
machine = Machine(model=BackTest2, states=states, transitions=transitions, initial='Init')bt2 = BackTest2(name='bt2',global_buffer_ip = wan_ip, space_name ='sp_qtv.bt001')
bt2._init_para(para_dict = strategy_para)

开始逐次运行测试,在实际使用时没个时隙唤起处理,然后再对具体的功能微调就可以了

res_tuple = bt2.get_data(dt_list = rec_dt_list, rec_list=rec_data_list)
if res_tuple is not None:print(bt2.meta['cash'] , bt2.meta['hold'])print(bt2.state)bt2.meta['last_dt'] = res_tuple[0]cur_data = res_tuple[1]bt2.ruleset(data=cur_data)else:print('next block')

测试1:测试模型分到达是否买入 9:32

Date: 2013-03-15 09:32:00
Record: {'data_dt': '2013-03-15 09:32:00', 'open': 3.13, 'close': 3.0, 'high': 3.14, 'low': 2.9, 'decision_score': 610}
6000 0
EBIn [155]: bt2.data
Out[155]:
{'code': '510300','buy_price': 3.0,'buy_dt': '2013-03-15 09:32:00','stocks': 1600,'buy_amt': 4800.0}

测试2:测试在8小时内,模型是否会hold住9没有在9:33卖出

Date: 2013-03-15 09:33:00
Record: {'data_dt': '2013-03-15 09:33:00', 'open': 3.13, 'close': 3.0, 'high': 3.14, 'low': 2.9, 'decision_score': 300}
1200.0 4800.0
HB
rate:  0.0In [157]: bt2.data
Out[157]:
{'code': '510300','buy_price': 3.0,'buy_dt': '2013-03-15 09:32:00','stocks': 1600,'buy_amt': 4800.0}

测试3:测试在8小时后,达到模型卖出分是否会卖出2013-03-16 09:33:00

Date: 2013-03-16 09:33:00
Record: {'data_dt': '2013-03-16 09:33:00', 'open': 3.13, 'close': 3.0, 'high': 3.14, 'low': 2.9, 'decision_score': 300}
1200.0 4800.0
HB
rate:  0.0
bIn [159]: bt2.data
Out[159]: {}In [160]: bt2.close_orders
Out[160]:
[{'code': '510300','buy_price': 3.0,'buy_dt': '2013-03-15 09:32:00','stocks': 1600,'buy_amt': 4800.0,'sell_price': 3.0,'sell_dt': '2013-03-16 09:33:00','sell_amt': 4800.0,'gp': 0.0,'np': -24.0,'npr': -0.005}]

测试4:测试卖出当日是否会再次买入2013-03-16 13:33:00

Date: 2013-03-16 13:33:00
Record: {'data_dt': '2013-03-16 13:33:00', 'open': 3.13, 'close': 3.0, 'high': 3.14, 'low': 2.9, 'decision_score': 601}
5976.0 0
EB
In [162]: bt2.data
Out[162]:
{'code': '510300','buy_price': 3.0,'buy_dt': '2013-03-16 13:33:00','stocks': 1600,'buy_amt': 4800.0}

测试5:测试模型达到持有时间上限后是否会卖出 2013-03-20 13:33:00

Date: 2013-03-20 13:33:00
Record: {'data_dt': '2013-03-20 13:33:00', 'open': 3.13, 'close': 3.0, 'high': 3.14, 'low': 2.9, 'decision_score': 601}
1176.0 4800.0
HB
rate:  -0.004
aIn [164]: bt2.data
Out[164]: {}In [165]: bt2.close_orders
Out[165]:
[{'code': '510300','buy_price': 3.0,'buy_dt': '2013-03-15 09:32:00','stocks': 1600,'buy_amt': 4800.0,'sell_price': 3.0,'sell_dt': '2013-03-16 09:33:00','sell_amt': 4800.0,'gp': 0.0,'np': -24.0,'npr': -0.005},{'code': '510300','buy_price': 3.0,'buy_dt': '2013-03-16 13:33:00','stocks': 1600,'buy_amt': 4800.0,'sell_price': 3.0,'sell_dt': '2013-03-20 13:33:00','sell_amt': 4800.0,'gp': 0.0,'np': -24.0,'npr': -0.005}]

测试6:在突然疯狂增长时,其状态可能不准确 2013-03-21 14:33:00 (EW1 - EW2)

Date: 2013-03-20 14:33:00
Record: {'data_dt': '2013-03-20 14:33:00', 'open': 3.13, 'close': 3.0, 'high': 3.14, 'low': 2.9, 'decision_score': 601}
5952.0 0
EBIn [169]: bt2.data
Out[169]:
{'code': '510300','buy_price': 3.0,'buy_dt': '2013-03-20 14:33:00','stocks': 1600,'buy_amt': 4800.0}同时可以看到全局资金也变少了
In [168]: bt2._get_global_control_meta(varname='monthly_quota')
Out[168]: 95200.0

测试7:止盈卖出(从打印c可以看到是订单本身的止盈卖出)

In [173]: bt2.close_orders
Out[173]:
[{'code': '510300','buy_price': 3.0,'buy_dt': '2013-03-15 09:32:00','stocks': 1600,'buy_amt': 4800.0,'sell_price': 3.0,'sell_dt': '2013-03-16 09:33:00','sell_amt': 4800.0,'gp': 0.0,'np': -24.0,'npr': -0.005},{'code': '510300','buy_price': 3.0,'buy_dt': '2013-03-16 13:33:00','stocks': 1600,'buy_amt': 4800.0,'sell_price': 3.0,'sell_dt': '2013-03-20 13:33:00','sell_amt': 4800.0,'gp': 0.0,'np': -24.0,'npr': -0.005},{'code': '510300','buy_price': 3.0,'buy_dt': '2013-03-20 14:33:00','stocks': 1600,'buy_amt': 4800.0,'sell_price': 13.0,'sell_dt': '2013-03-21 14:33:00','sell_amt': 20800.0,'gp': 16000.0,'np': 15896.0,'npr': 3.3117}]

测试8:订单止损卖出

Date: 2013-03-21 14:59:00
Record: {'data_dt': '2013-03-21 14:59:00', 'open': 3.13, 'close': 13.1, 'high': 3.14, 'low': 2.9, 'decision_score': 610}
21848.0 0
EW1In [175]: bt2.data
Out[175]:
{'code': '510300','buy_price': 13.1,'buy_dt': '2013-03-21 14:59:00','stocks': 300,'buy_amt': 3930.0}In [176]: res_tuple = bt2.get_data(dt_list = rec_dt_list, rec_list=rec_data_list)...: if res_tuple is not None:...:     print(bt2.meta['cash'] , bt2.meta['hold'])...:     print(bt2.state)...:     bt2.meta['last_dt'] = res_tuple[0]...:     cur_data = res_tuple[1]...:     bt2.ruleset(data=cur_data)...:...: else:...:     print('next block')...:
Date: 2013-03-22 14:00:00
Record: {'data_dt': '2013-03-22 14:00:00', 'open': 3.13, 'close': 0.1, 'high': 3.14, 'low': 2.9, 'decision_score': 610}
17918.0 3930.0
HW1
rate:  1.9913333333333334
d

4 结论

整体上,这个回测对象是可以使用的。

不必纠结于细节,可以直接进入下一步工程:主要是block规范的实现。数据的请求均是以block为单位,通过block manager实现。所以回测对象还需要被上一层的对象调用,形成worker - player模式。

另外,可以假设日数据可用(可盈利),试着以日收盘为周期建模,看效果。

这篇关于Python 算法交易实验68 回测对象重构的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/815341

相关文章

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

Python中win32包的安装及常见用途介绍

《Python中win32包的安装及常见用途介绍》在Windows环境下,PythonWin32模块通常随Python安装包一起安装,:本文主要介绍Python中win32包的安装及常见用途的相关... 目录前言主要组件安装方法常见用途1. 操作Windows注册表2. 操作Windows服务3. 窗口操作

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

python常用的正则表达式及作用

《python常用的正则表达式及作用》正则表达式是处理字符串的强大工具,Python通过re模块提供正则表达式支持,本文给大家介绍python常用的正则表达式及作用详解,感兴趣的朋友跟随小编一起看看吧... 目录python常用正则表达式及作用基本匹配模式常用正则表达式示例常用量词边界匹配分组和捕获常用re

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

python删除xml中的w:ascii属性的步骤

《python删除xml中的w:ascii属性的步骤》使用xml.etree.ElementTree删除WordXML中w:ascii属性,需注册命名空间并定位rFonts元素,通过del操作删除属... 可以使用python的XML.etree.ElementTree模块通过以下步骤删除XML中的w:as

使用Python绘制3D堆叠条形图全解析

《使用Python绘制3D堆叠条形图全解析》在数据可视化的工具箱里,3D图表总能带来眼前一亮的效果,本文就来和大家聊聊如何使用Python实现绘制3D堆叠条形图,感兴趣的小伙伴可以了解下... 目录为什么选择 3D 堆叠条形图代码实现:从数据到 3D 世界的搭建核心代码逐行解析细节优化应用场景:3D 堆叠图

深度解析Python装饰器常见用法与进阶技巧

《深度解析Python装饰器常见用法与进阶技巧》Python装饰器(Decorator)是提升代码可读性与复用性的强大工具,本文将深入解析Python装饰器的原理,常见用法,进阶技巧与最佳实践,希望可... 目录装饰器的基本原理函数装饰器的常见用法带参数的装饰器类装饰器与方法装饰器装饰器的嵌套与组合进阶技巧

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到

Python get()函数用法案例详解

《Pythonget()函数用法案例详解》在Python中,get()是字典(dict)类型的内置方法,用于安全地获取字典中指定键对应的值,它的核心作用是避免因访问不存在的键而引发KeyError错... 目录简介基本语法一、用法二、案例:安全访问未知键三、案例:配置参数默认值简介python是一种高级编