十字星形态图,在股市中的应用:
十字星是一种K线基本型态。十字星,是一种只有上下影线,没有实体的K线图。开盘价即是收盘价,表示在交易中,股价出现高于或低于开盘价成交,但收盘价与开盘价相等。其中:上影线越长,表示卖压越重。下影线越长,表示买盘旺盛。通常在股价高位或低位出现十字线,可称为转机线,意味着出现反转。
以上的文字笔者截取自百度百科,笔者对以上的定义做个解读:十字星作为反转形态出现,出现在底部那么就会上涨,出现在顶部,那么就会下跌,根据这个解读,就得出一个策略:底部十字星,全仓买入,顶部十字星,全仓卖出。
综上:今天笔者要回测的策略为:底部十字星,全仓买入,顶部十字星,全仓卖出
先上代码和结论:
import tushare as ts import pandas as pd import datetime # For datetime objects import os.path # To manage paths import sys # To find out the script name (in argv[0]) # Import the backtrader platform import backtrader as bt import talib as talib import numpy as np class MyStrategy(bt.Strategy): # 策略参数 params = dict( printlog=False ) def __init__(self): self.star = dict() # 定义全局变量 self.count = 0 for data in self.datas: # 转为tabib要求的数据格式 opens = np.array(data.open.array) highs = np.array(data.high.array) lows = np.array(data.low.array) closes = np.array(data.close.array) print(opens) # 计算十字星数据,结果为-100底部十字星,结果为100顶部十字星,0非十字星 res = talib.CDLDOJISTAR(opens, highs, lows, closes) # 数据放入self中 self.star[data._id] = res def next(self): # 得到当前的账户价值 total_value = self.broker.getcash() for data in self.datas: pos = self.getposition(data).size # 函数出现100就代表出现十字星形态,做买入 if total_value > 0 and self.star[data._id][self.count] == -100: p_value = total_value * 0.9 / 10 size = ((int(total_value / self.data.close[0]))) - ((int(total_value / self.data.close[0])) % 100) - 100 self.buy(data=data, size=size) print('出现底部十字星,全仓买入,买入数量' + str(size) ) # 买入后的出现顶部十字星全仓后卖出 if pos > 0 and self.star[data._id][self.count] == 100: # 全部卖出 # 跟踪订单避免重复 self.sell(data=data, size=pos) print('出现顶部十字星,卖出数量' + str(pos) ) #自增处理 self.count = self.count + 1 def log(self, txt, dt=None, doprint=False): if self.params.printlog or doprint: dt = dt or self.datas[0].datetime.date(0) print(f'{dt.isoformat()},{txt}') # 记录交易执行情况(可省略,默认不输出结果) def notify_order(self, order): # 如果order为submitted/accepted,返回空 if order.status in [order.Submitted, order.Accepted]: return # 如果order为buy/sell executed,报告价格结果 if order.status in [order.Completed]: if order.isbuy(): self.log(f'买入:\n价格:{order.executed.price:.2f},\ 成本:{order.executed.value:.2f},\ 数量:{order.executed.size:.2f},\ 手续费:{order.executed.comm:.2f}') self.buyprice = order.executed.price self.buycomm = order.executed.comm else: self.log(f'卖出:\n价格:{order.executed.price:.2f},\ 成本: {order.executed.value:.2f},\ 数量:{order.executed.size:.2f},\ 手续费{order.executed.comm:.2f}') self.bar_executed = len(self) # 如果指令取消/交易失败, 报告结果 elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('交易失败') self.order = None # 记录交易收益情况(可省略,默认不输出结果) def notify_trade(self, trade): if not trade.isclosed: return self.log(f'策略收益:\n毛收益 {trade.pnl:.2f}, 净收益 {trade.pnlcomm:.2f}') pro = ts.pro_api('cbb257058b7cb228769b4949437c27c27e5132e882747dc80f01a5a5') def ts_get_daily_stock(code, start_dt, end_dt): start_dt = start_dt.replace("'", "", 3); end_dt = end_dt.replace("'", "", 3); # start_dt = '20190101' # end_dt='' print(code, start_dt, end_dt) data = pro.daily(ts_code=code, start_date=start_dt, end_date=end_dt) data['trade_date'] = pd.to_datetime(data['trade_date']) data['trade_date'] = pd.to_datetime(data['trade_date']) data = data.sort_values(by='trade_date') data.index = data['trade_date'] data['openinterest'] = 0 data['volume'] = data['vol'] data = data[ ['open', 'close', 'high', 'low', 'volume'] ] return data # 读取选股的结果 df = pd.read_csv('stock_alpha.csv') df.columns = ['ts_code', 'name', 'alpha', 'start_dt', 'end_dt'] min_a = df.sort_values(by='alpha') min_a = min_a.iloc[:10, :] code = [] code = min_a['ts_code'] # 股票代码 start_dts = [] start_dts = min_a['start_dt'] # 股票代码起始时间 end_dts = [] end_dts = min_a['end_dt'] # 股票代码结束时间 for i in range(len(code)): data = ts_get_daily_stock(code.iloc[i], start_dts.iloc[i], end_dts.iloc[i]) # 字段分别为股票代码、开始日期、结束日期 data.to_csv(code.iloc[i] + '.csv') cerebro = bt.Cerebro() for i in range(len(code)): # 循环获取股票历史数据 dataframe = pd.read_csv(code.iloc[i] + '.csv', index_col=0, parse_dates=True) dataframe['openinterest'] = 0 data = bt.feeds.PandasData(dataname=dataframe, fromdate=datetime.datetime(2008, 2, 20), todate=datetime.datetime(2022, 4, 5) ) cerebro.adddata(data) # 回测设置 startcash = 100000.0 cerebro.broker.setcash(startcash) # 设置佣金为千分之一 cerebro.broker.setcommission(commission=0.001) # 添加策略 cerebro.addstrategy(MyStrategy, printlog=True) cerebro.run() # 获取回测结束后的总资金 portvalue = cerebro.broker.getvalue() pnl = portvalue - startcash # 打印结果 print(f'总资金: {round(portvalue,2)}') print(f'净收益: {round(pnl,2)}') cerebro.plot()
总资金: 85693.93
净收益: -14306.07
笔者的数据是依旧是中国国航 601111,csv的文件,前面的文章可以获取到,此处不再放出连接
结论是亏损,看来单纯的用十字星来作为反转形态,作为买卖点,针对中国国航是不可靠的,如果还有同学想要回测其他股票,可以下载csv修改,非软件专业的也可以,联系笔者,我帮着回测。
本文重点:介绍一个函数
talib.CDLDOJISTAR(opens, highs, lows, closes)
计算十字星数据的函数,结果为-100底部十字星,结果为100顶部十字星,0非十字星