看kdj炒股靠谱吗
上一篇回测了均线策略,当时选的是茅台(600519)和平安(000001)作为测试数据。通过对不同的均线设置,回测出不同的结果。如果忘记了或者第一次看这篇文字,不妨先看看我的前一篇内容:量化程序员小伙告诉你:均线策略真的有用吗?
有不少朋友留言评论和私信,大体是不看好均线单个指标,因为量化效果好不好,到后面好像只有茅台这样的标的才能赚钱,还是和选股有很大关系。但是到底是不是这样呢?我随机扫描了市场大部分的票,并设置不同的均线进行回测。
不同的均线回测结果
是不是很意外,盈利和成功率没有想象中的低。所以基于此,加一个技术指标是不是会更好呢?说干就干,黄sir决定加一个kdj指标进去。所以双均线策略和kdj策略为:kdj上穿买入,短均线下穿长均线并且kdj下穿卖出。
kdj是常用的指标,它的中文名叫随机指标。通过一个特定的周期(常为9日、9周等)内出现过的最高价、最低价及最后一个计算周期的收盘价及这三者之间的比例关系,来计算最后一个计算周期的未成熟随机值RSV,然后根据平滑移动平均线的方法来计算K值、D值与J值。
RSV的计算公式
RSV计算公式
C为当天的收盘价;Ln为之前n日内的最低价;Hn为之前n日内的最高价。
翻译成通俗易懂的:RSV = (收盘价-N周期最低价)/(N周期最高价-N周期最低价)*100
K = RSV的N周期加权移动平均值
D = K值的N周期加权移动平均值
J值 = 3K-2D
还是使用backtrader,它内置了talib指标计算公式,使用起来非常方便。
第一步,安装backtrader。
pip install backtrader
第二步,准备数据。
我已经利用之前的开源代码提前下载了数据,以股票代码为名的csv文件。
数据
每个csv文件包含日期,开盘价,收盘价,最高价,最低价,成交量等。
第三步,编写代码。
因为有均线策略回测代码基础,因此我复制了里面大部分内容,只需要添加和修改部分内容即可。策略命名为MyStrategy,在两个均线变量(ma_1、ma_2)基础上新增period和ema_period两个变量用于计算kdj。
class MyStrategy(bt.Strategy): params = ( ('ma_1', 5), ('ma_2', 10), ('period', 9), ('ema_period', 3), )
根据计算公式,计算就比较简单了。
def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose = self.datas[0].close # To keep track of pending orders and buy price/commission self.order = None self.buyprice = None self.buycomm = None self.highest_price = bt.indicators.Highest(self.data.high, period=self.params.period) self.lowest_price = bt.indicators.Lowest(self.data.low, period=self.params.period) # 计算rsv值 self.rsv = 100 * bt.DivByZero( self.data_close - self.highest_price, self.highest_price - self.lowest_price, zero=None ) # 计算rsv的3周期加权平均值,即K值 self.K = bt.indicators.EMA(self.rsv, period=self.params.ema_period) # D值=K值的3周期加权平均值 self.D = bt.indicators.EMA(self.K, period=self.params.ema_period) # J=3*K-2*D self.J = 3 * self.K - 2 * self.D # kdj条件 self.kdj = self.J - self.D # 短均线 self.short_sma = bt.indicators.SimpleMovingAverage(period=self.params.ma_1) # 长均线 self.long_sma = bt.indicators.SimpleMovingAverage(period=self.params.ma_2) # 均线条件 self.sma_condition = self.short_sma - self.long_sma
注意,我在均线策略代码中sma5和sma10现在改成short_sma和long_sma,因为这两个值可以随时修改,比如20日均线和60均线。根据策略条件调整买入和卖出:
def next(self): # self.log('收盘, %.2f' % self.dataclose[0]) # 检查是否正在准备下单,如果是则直接返回 if self.order: return # 检查是否持仓 if not self.position: # 没有仓位,执行买入条件判断: # self.sma_condition[0] > 0 and self.sma_condition[-1] < 0 and if self.kdj[0] > 0 and self.kdj[-1] < 0: self.log('买入, %.2f' % self.dataclose[0]) # 买入 self.order = self.buy() else: # 执行条件卖出 # self.sm_condition[0] < 0 and if self.sma_condition[0] < 0 and self.kdj[0] < 0: self.log('卖出, %.2f' % self.dataclose[0]) # 卖出 self.order = self.sell()
其他的地方和均线策略的代码一样,不用修改。为了扫描更多的数据,我把公用地封装了一个函数,并命名为run。
def run(item_code): cerebro = bt.Cerebro() # 加载我们的策略 cerebro.addstrategy(MyStrategy) df = get_symbol(item_code, adjust="hfq", downloaded=False) new_df = df[["日期", "开盘", "收盘", "最高", "最低", "成交量"]] new_df.columns = ["trade_date", "open", "close", "high", "low", "volume"] new_df["trade_date"] = pd.to_datetime(new_df["trade_date"]) new_df.set_index("trade_date", inplace=True) new_df['openinterest'] = 0 data = bt.feeds.PandasData( dataname=new_df, fromdate=datetime.datetime(2010, 1, 1), todate=datetime.datetime(2021, 12, 15) ) cerebro.adddata(data) # 初始资金 init_amount = 300000.0 cerebro.broker.setcash(init_amount) # 设置每笔交易交易的股票数量 cerebro.addsizer(bt.sizers.FixedSize, stake=100) # 手续费 cerebro.broker.setcommission(commission=0.0) # 运行策略 cerebro.run() # 结果 print('初始资金: %.2f' % init_amount) print('期末资金: %.2f' % cerebro.broker.getvalue()) # cerebro.plot()
run接收一个参数item_code:股票代码,这样就可以根据传进来的不同的股票代码进行验证。
代码已经完成,5日均线和10日均线,先验证600519吧。
kdj上穿买入,5日均线下穿10日均线且kdj下穿卖出
初始资金: 300000.00,期末资金: 867891.00,翻倍了!相比单个均线策略收益高了很多。
当然,单纯的几个票不能看出什么,扫描大部分的票的情况怎么样呢?下一篇揭晓。
最后,如果希望看到更多关于量化方面的内容,记得加一个关注,以免迷路。