这个周末话了2天把我的回测系统写完了,时间驱动回测,时间是核心,按真是的涨跌幅,价格进行交易,今天简单看一下后面给仔细的说明
链接 小果量化回测系统v1----简单的回测多线程,提供源代码 (qq.com)
回测长白山的源代码,简单的均线策略
from xgtrader_backtrader.backtrader import backtrader
from xgtrader_backtrader.user_def_data.user_def_data import user_def_datafrom xgtrader_backtrader.trader_tool import tdx_indicator import pandas as pd class my_backtrader: ''' 多标的均线策略 外面可用采用提前计算买卖点的方式 也可用实时计算 ''' def __init__(self,start_date='20210105',end_date='20500101',data_type='D', starting_cash=10000,commission=0.001): self.start_date=start_date self.end_date=end_date self.data_type=data_type self.starting_cash=starting_cash self.commission=commission self.stock_list=['603099'] self.amount=100 self.trader=backtrader(start_date=self.start_date,end_date=self.end_date, data_type=self.data_type,starting_cash=self.start_date,commission=self.commission) self.data=user_def_data(start_date=self.start_date,end_date=self.end_date,data_type=self.data_type) def add_all_data(self): ''' 多线程加载数据 ''' self.data.get_thread_add_data(stock_list=self.stock_list) self.hist=self.data.hist return self.hist def get_cacal_all_indicators(self): ''' 计算全部的指标 ''' hist=self.add_all_data() trader_info=pd.DataFrame() #拆分数据 for stock in self.stock_list: df=hist[hist['stock']==stock] df['mean_5']=df['close'].rolling(5).mean() df['mean_10']=df['close'].rolling(10).mean() df['buy']=df['mean_5']>df['mean_10'] df['sell']=df['mean_5']<df['mean_10'] trader_info=pd.concat([trader_info,df],ignore_index=True) return trader_info def run_backtrader(self): ''' 运行回测 ''' trader_list=self.trader.get_trader_date_list() trader_info=self.get_cacal_all_indicators() for date in trader_list: df=trader_info[trader_info['date']==date] stock_list=df['stock'].tolist() for stock in stock_list: df1=df[df['stock']==stock] price=df1['close'].tolist()[-1] price=float(price) buy=df1['buy'].tolist()[-1] sell=df1['sell'].tolist()[-1] if buy==True: if self.trader.check_stock_is_av_buy(date=date,stock=stock,price=price,amount=self.amount): self.trader.buy(date=date,stock=stock,price=price,amount=self.amount) else: self.trader.settle(date=date,stock=stock,price=price) elif sell==True: if self.trader.check_stock_is_av_sell(date=date,stock=stock,price=price,amount=self.amount): self.trader.sell(date=date,stock=stock,price=price,amount=self.amount) else: self.trader.settle(date=date,stock=stock,price=price) else: self.trader.settle(date=date,stock=stock,price=price) if __name__=='__main__': trader=my_backtrader() trader.run_backtrader() all_trader_data=trader.trader.get_position_all_trader_data() all_hold_stock=trader.trader.get_total_position_pandas_data() print(all_hold_stock) all_trader_data.to_excel(r'全部的交易数据.xlsx') account=trader.trader.get_total_portfolio_pandas_data() print(account) account.to_excel(r'全部的数据.xlsx') #个股的交易数据 df=trader.trader.get_position_pandas_data_by_stock(stock='603099') print(df) df.to_excel(r'个股交易数据.xlsx')
框架非常的开放,内部封装了数据交易检查
回测的结果
大概3秒完成,数据结果
外面看全部的交易数据
全部的账户数据
个股的交易数据
源代码全部上传可用加入下载,后面对接实盘,先实盘,回测一体
最后3 张
回测框架源代码
from xgtrader_backtrader.data.data import datafrom xgtrader_backtrader.portfolio.portfolio import portfolio from xgtrader_backtrader.position.position import position from xgtrader_backtrader.indicators.indicators import indicators from xgtrader_backtrader.trader_tool.stock_data import stock_data import pandas as pd class backtrader: def __init__(self,start_date='20210105',end_date='20500101',data_type='D',starting_cash=10000,cash=10000,commission=0.001): self.start_date=start_date self.end_date=end_date self.data_type=data_type self.commission=commission self.data=data(start_date=self.start_date,end_date=self.end_date) self.position=position(start_date=self.start_date,end_date=self.end_date,starting_cash=starting_cash, data_type=self.data_type,commission=commission,cash=cash) self.portfolio=portfolio(starting_cash=starting_cash,cash=cash) self.stock_data=stock_data() def check_is_creat_data(self,date='20230101',stock='60031',price=1,amount=100,trader_type='buy'): ''' 检查是否建立数据 ''' #建立账户 if stock in list(self.position.position.keys()): #print('{} {}数据已经建立'.format(date,stock)) #print('{} {}数据账户建立'.format(date,stock)) return True else: #添加数据 print('{}数据没有建立开始建立'.format(stock)) self.data.get_add_data(stock=stock) print('{}账户没有建立开始建立'.format(stock)) self.position.creat_position(stock=stock,start_date=date,price=price,amount=amount,trader_type='buy') return False def buy(self,date='20230101',stock='600031',price=1,amount=100,trader_type='buy'): ''' 买入 date交易时间 stock股票代码 price交易价格 amount数量 trader_type交易类型 ''' #检查数据是否加载 if self.check_is_creat_data(date=date,stock=stock,price=price,amount=amount)==True: self.position.adjust_position_data(trader_type=trader_type,stock=stock,date=date,price=price,amount=amount) return True, date ,stock,price,amount,trader_type else: print('数据没有建立建立数据{}'.format(stock,date)) return False, date ,stock,price,amount,trader_type def sell(self,date='20230101',stock='600031',price=1,amount=100,trader_type='sell'): ''' 卖出 date交易时间 stock股票代码 price交易价格 amount数量 trader_type交易类型 ''' #检查数据是否加载 if self.check_is_creat_data(date=date,stock=stock,price=price,amount=amount)==True: self.position.adjust_position_data(trader_type=trader_type,stock=stock,date=date,price=price,amount=amount) return True, date ,stock,price,amount,trader_type else: print('数据没有建立建立数据{}'.format(stock,date)) return False, date ,stock,price,amount,trader_type def settle(self,date='20230101',stock='600031',price=1,trader_type='settle',amount=100,): ''' 结算函数,持股结算 只有持有账户价值变化 date交易时间 stock股票代码 price交易价格 amount数量这个不需要为了兼容保留 trader_type交易类型 ''' #检查数据是否加载 if self.check_is_creat_data(date=date,stock=stock,price=price,amount=amount)==True: self.position.adjust_position_data(trader_type=trader_type,stock=stock,date=date,price=price,amount=amount) return True, date ,stock,price,amount,trader_type else: print('数据没有建立建立数据{}'.format(stock,date)) return False, date ,stock,price,amount,trader_type def get_trader_date_list(self): ''' 获取交易日历 ''' trader_time=self.stock_data.get_trader_date_list(start_date=self.start_date,end_date=self.end_date) return trader_time def get_position_dict_data(self): ''' 获取持股数据字典类型的数据 ''' dict_data=self.position.position return dict_data def get_position_dict_data_by_stock(self,stock='600031'): ''' 获取持股数据字典类型的数据通过代码 ''' if stock in list(self.position.position.keys()): dict_data=self.position.position[stock] return dict_data else: print('{}没有建立持股'.format(stock)) return {} def get_position_pandas_data_by_stock(self,stock='600031'): ''' 获取持股数据字典类型的数据 ''' if stock in list(self.position.position.keys()): dict_data=self.position.position[stock] df=pd.DataFrame(dict_data) return df else: print('{}没有建立持股'.format(stock)) df=pd.DataFrame() return df def get_total_position_pandas_data(self): ''' 合并总持股数据 ''' df=self.position.get_total_position() return df def get_position_all_trader_data(self): ''' 获取全部交易数据 ''' df=self.position.get_total_position_trader() return df def get_total_portfolio_dict_data(self): ''' 获取总账户字典数据 ''' df=self.position.portfolio.total_portfolio return df def get_total_portfolio_pandas_data(self): ''' 获取总账户字典数据 ''' df=self.position.portfolio.get_portfolio_data_to_pandas() return df def get_portfolio_last_data(self): ''' 获取账户最新的数据 ''' df=self.get_total_portfolio_pandas_data() data_dict={} data_dict['date']=df['date'].tolist()[-1] data_dict['stock_total_value']=df['stock_total_value'].tolist()[-1] data_dict['available_cash']=df['available_cash'].tolist()[-1] data_dict['ups_downs_value']=df['ups_downs_value'].tolist()[-1] data_dict['reference_profit']=df['reference_profit'].tolist()[-1] data_dict['host_cost']=df['host_cost'].tolist()[-1] data_dict['cumsum_host_cost']=df['cumsum_host_cost'].tolist()[-1] data_dict['total_value']=df['total_value'].tolist()[-1] data_dict['return_ratio']=df['return_ratio'].tolist()[-1] data_dict['cumsum_return_ratio']=df['cumsum_return_ratio'].tolist()[-1] return data_dict def get_position_last_data_by_stock(self,stock='600031'): ''' 获取个股最新持股数据 ''' if stock in list(self.position.position.keys()): data_dict={} df=self.get_position_pandas_data_by_stock(stock=stock) data_dict['stock']=df['stock'].tolist()[-1] data_dict['price']=df['price'].tolist()[-1] data_dict['date']=df['date'].tolist()[-1] data_dict['host_cost']=df['host_cost'].tolist()[-1] data_dict['cumsum_hold_cost']=df['cumsum_hold_cost'].tolist()[-1] data_dict['amount']=df['amount'].tolist()[-1] data_dict['trader_amount']=df['trader_amount'].tolist()[-1] data_dict['trader_value']=df['trader_value'].tolist()[-1] data_dict['value']=df['value'].tolist()[-1] data_dict['price_limit']=df['price_limit'].tolist()[-1] data_dict['ups_downs_value']=df['ups_downs_value'].tolist()[-1] data_dict['return']=df['return'].tolist()[-1] data_dict['cumsum_return']=df['cumsum_return'].tolist()[-1] data_dict['trader_type']=df['trader_type'].tolist()[-1] return data_dict else: print('{}没有建立持股'.format(stock)) return {} def check_stock_is_av_buy(self,date='',stock='128036',price='156.700',amount=10): ''' 检查是否可用买入 ''' account=self.get_portfolio_last_data() if stock not in list(self.position.position.keys()): print('时间{} {}没有持股直接买入'.format(date,stock)) return True else: buy_value=price*amount av_cash=account['available_cash'] com=price*amount*self.commission if av_cash>=buy_value+com: print('时间{} {}允许买入 可用资金{} 买入价值{} 手续费{}'.format(date,stock,av_cash,buy_value,com)) return True else: print('时间{} {}不允许买入 可用资金{} 小于买入价值{} 加手续费{}'.format(date,stock,av_cash,buy_value,com)) return False def check_stock_is_av_sell(self,date='',stock='128036',price='156.700',amount=10): ''' 检查是否可用卖出 ''' hold_stock=self.get_position_last_data_by_stock(stock=stock) if stock not in list(self.position.position.keys()): print('时间{} {}没有持股不允许卖出'.format(date,stock)) return False else: sell_amount=amount hold_amount=hold_stock['amount'] if hold_amount>=sell_amount: print('时间{} {} 允许卖出 持有数量{} 卖出数量{}'.format(date,stock,hold_amount,sell_amount)) return True else: print('时间{} {} 不允许卖出 持有数量{} 小于卖出数量{}'.format(date,stock,hold_amount,sell_amount)) return False