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和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

python常见环境管理工具超全解析

《python常见环境管理工具超全解析》在Python开发中,管理多个项目及其依赖项通常是一个挑战,下面:本文主要介绍python常见环境管理工具的相关资料,文中通过代码介绍的非常详细,需要的朋友... 目录1. conda2. pip3. uvuv 工具自动创建和管理环境的特点4. setup.py5.

Python常用命令提示符使用方法详解

《Python常用命令提示符使用方法详解》在学习python的过程中,我们需要用到命令提示符(CMD)进行环境的配置,:本文主要介绍Python常用命令提示符使用方法的相关资料,文中通过代码介绍的... 目录一、python环境基础命令【Windows】1、检查Python是否安装2、 查看Python的安

Python UV安装、升级、卸载详细步骤记录

《PythonUV安装、升级、卸载详细步骤记录》:本文主要介绍PythonUV安装、升级、卸载的详细步骤,uv是Astral推出的下一代Python包与项目管理器,主打单一可执行文件、极致性能... 目录安装检查升级设置自动补全卸载UV 命令总结 官方文档详见:https://docs.astral.sh/

Python并行处理实战之如何使用ProcessPoolExecutor加速计算

《Python并行处理实战之如何使用ProcessPoolExecutor加速计算》Python提供了多种并行处理的方式,其中concurrent.futures模块的ProcessPoolExecu... 目录简介完整代码示例代码解释1. 导入必要的模块2. 定义处理函数3. 主函数4. 生成数字列表5.

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

Python虚拟环境与Conda使用指南分享

《Python虚拟环境与Conda使用指南分享》:本文主要介绍Python虚拟环境与Conda使用指南,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、python 虚拟环境概述1.1 什么是虚拟环境1.2 为什么需要虚拟环境二、Python 内置的虚拟环境工具

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

Python pip下载包及所有依赖到指定文件夹的步骤说明

《Pythonpip下载包及所有依赖到指定文件夹的步骤说明》为了方便开发和部署,我们常常需要将Python项目所依赖的第三方包导出到本地文件夹中,:本文主要介绍Pythonpip下载包及所有依... 目录步骤说明命令格式示例参数说明离线安装方法注意事项总结要使用pip下载包及其所有依赖到指定文件夹,请按照以