通用先引用乌云压顶的K线形态,定义以及理论意义:
K线卖出口诀:乌云压顶,卖出要紧
这里讲的“乌云”,是指股价上升到高位后,某日出现一条高开低走的大阴线,罩在前面一条阳线的头上,称之为“乌云压顶”。该形态的出现,表明获利盘在回吐筹码,股价将会出现一段下调行情,应卖出股票。
乌云压顶形态又称乌云线形态,是K线图较为常见顶部转形态图表之一。这种形态由两根K线组成,它们一般出现在上升趋势之后,在有些情况下也可能出现在水平调整区间的顶部。
乌云压顶(Dark-Cloud Cover)经常发生在一段上升行情的顶部,由一阴一阳两根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.cloudcover = 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)
# 乌云盖顶形态
cloudcover = talib.CDLDARKCLOUDCOVER(opens, highs, lows, closes)
# 数据放入self中
print('十字星数据')
self.star[data._id] = res
print('乌云盖顶数据')
self.cloudcover[data._id] = cloudcover
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
if(size > 100 ):
self.buy(data=data, size=size)
print('出现底部十字星,全仓买入,买入数量' + str(size) )
if pos > 0 and self.cloudcover[data._id][self.count] == 100 or self.cloudcover[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()
回测结果
总资金: 93905.92
净收益: -6094.08
笔者回测的数据依旧是中国国航的数据,结果是亏损的。
本章节和上一章节的内容差异不大,只是引入了一个新的乌云盖顶形态函数:
talib.CDLDARKCLOUDCOVER(opens, highs, lows, closes)
结果还是100或者-100