金融量化-基于K线形态锤子线的趋势跟踪策略
1.基本原理
1.1 K线部位定义:
实体:某一根K线开盘价和收盘价之间部分;
上影线:某一根K线最高价到实体上端的部分;
下影线:某一根K线最低价到实体下端的部分;
1.2 锤子线定义
实体处于整个价格区间上端,实体颜色本身不影响;
下影线长度至少达到实体高度的2倍;
上影线很短;
1.3 策略原理
在下跌过程中,当某一日出现锤子线,意味着当天行情先继续下跌后出现大幅反弹,行情可能由此反转;
由此以观察期均线识别趋势下跌,以下跌趋势中出现锤子线作为开仓信号; 采用移动止损方式进行止损构建此策略;
1.4 止损条件
当天最低价 < max(均价-观察期内一定倍数的标准差,开仓价-开仓时标准差);
1.5 形态要点:
在出现锤头线(锤子线)之前,股价需经过一段时间的下跌后,处于下跌趋势中,此时出现此形态才具有参考意义;
锤头实体越小,下影线越长,止跌作用就越明显,参考价值越大;
2.策略实现
2.1 收集并计算所需数据
import pandas as pd
import numpy as np
import tushare as ts
code = '002398' # 股票代码
body_size = 0.03 # 表示锤子实体大小上限,基准为当日开盘价,实体不能太大,波动范围限制在3%;
head_size = 0.5 # 表示锤子上影线长度上限,基准为下影线长度,上影线要短一点,不能超过下影线的的一半;
tail_size = 2 # 表示下影线与实体大小比值,下影线要大于实体两倍;
length = 10 # 表示观察期时间长短;
stoplose_trigger = 1 # 表示当价格偏离均线满足几倍标准差时止损
data.sort_index(ascending=True, inplace=True)
data.head()
open | high | close | low | volume | amount | |
---|---|---|---|---|---|---|
date | ||||||
2012-01-04 | 6.64 | 6.80 | 6.40 | 6.39 | 283430.0 | 4564127.0 |
2012-01-05 | 6.38 | 6.40 | 5.76 | 5.76 | 820954.0 | 12005136.0 |
2012-01-06 | 5.71 | 5.83 | 5.70 | 5.43 | 972637.0 | 13330505.0 |
2012-01-09 | 5.69 | 5.97 | 5.94 | 5.57 | 536522.0 | 7710121.0 |
2012-01-10 | 5.94 | 6.27 | 6.21 | 5.94 | 1121594.0 | 17023694.0 |
data.reset_index(inplace=True) #把索引设置成为默认;为了后面交易策略逻辑循环更方便一些;
data.head()
date | open | high | close | low | volume | amount | |
---|---|---|---|---|---|---|---|
0 | 2012-01-04 | 6.64 | 6.80 | 6.40 | 6.39 | 283430.0 | 4564127.0 |
1 | 2012-01-05 | 6.38 | 6.40 | 5.76 | 5.76 | 820954.0 | 12005136.0 |
2 | 2012-01-06 | 5.71 | 5.83 | 5.70 | 5.43 | 972637.0 | 13330505.0 |
3 | 2012-01-09 | 5.69 | 5.97 | 5.94 | 5.57 | 536522.0 | 7710121.0 |
4 | 2012-01-10 | 5.94 | 6.27 | 6.21 | 5.94 | 1121594.0 | 17023694.0 |
data['pct_change'] = data['close'].pct_change()
data['ma'] = data['close'].rolling(length).mean()
data['std'] = data['close'].rolling(length).std()
del data['volume']
del data['amount']
data.tail()
date | open | high | close | low | pct_change | ma | std | |
---|---|---|---|---|---|---|---|---|
1188 | 2016-12-26 | 12.10 | 12.57 | 12.42 | 11.98 | 0.023908 | 12.141 | 0.161620 |
1189 | 2016-12-27 | 12.34 | 12.47 | 12.34 | 12.32 | -0.006441 | 12.179 | 0.158986 |
1190 | 2016-12-28 | 12.34 | 12.45 | 12.38 | 12.31 | 0.003241 | 12.233 | 0.117289 |
1191 | 2016-12-29 | 12.41 | 12.59 | 12.49 | 12.27 | 0.008885 | 12.273 | 0.130559 |
1192 | 2016-12-30 | 12.41 | 12.55 | 12.50 | 12.27 | 0.000801 | 12.305 | 0.143778 |
由于实盘中当天的日线级别参考指标未实现,因此使用昨日参考指标指导当日交易,避免未来函数;
data['yes_ma'] = data['ma'].shift(1) #昨天的mean和昨天的std;
data['yes_std'] = data['std'].shift(1)
2.2 识别锤子形态
计算实体,上影线,下影线
data['body'] = abs(data['open'] - data['close']) #计算K线实体;
data['head'] = data['high'] - data[['open', 'close']].max(axis = 1 ) #计算上影线,按行计算
data['tail'] = data[['open', 'close']].min(axis=1) - data['low'] #计算下影线
data.head()
date | open | high | close | low | pct_change | ma | std | yes_ma | yes_std | body | head | tail | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2012-01-04 | 6.64 | 6.80 | 6.40 | 6.39 | NaN | NaN | NaN | NaN | NaN | 0.24 | 0.16 | 0.01 |
1 | 2012-01-05 | 6.38 | 6.40 | 5.76 | 5.76 | -0.100000 | NaN | NaN | NaN | NaN | 0.62 | 0.02 | 0.00 |
2 | 2012-01-06 | 5.71 | 5.83 | 5.70 | 5.43 | -0.010417 | NaN | NaN | NaN | NaN | 0.01 | 0.12 | 0.27 |
3 | 2012-01-09 | 5.69 | 5.97 | 5.94 | 5.57 | 0.042105 | NaN | NaN | NaN | NaN | 0.25 | 0.03 | 0.12 |
4 | 2012-01-10 | 5.94 | 6.27 | 6.21 | 5.94 | 0.045455 | NaN | NaN | NaN | NaN | 0.27 | 0.06 | 0.00 |
判断K线各部分是否符合锤子线要求
data['body_cond'] = np.where(data['body']/data['open'] < body_size, 1, 0) #实体的大小比开盘价要小于3%,K线实体不能太大;
data['head_cond'] = np.where(data['tail']==0, False, data['head'] / data['tail'] < head_size) #上影线不能比下影线的一半长;
# 当尾部长度为0,为防止判断除法报错,两步判断;
# data['head_cond'] = np.where(data['head']/data['tail'] < head_size, 1, 0) 有可能tail = 0
data['tail_cond'] = np.where(data['body']==0, True, (data['tail']/data['body']) > tail_size) #下影线要比实体的两倍更长才满足条件;
data.head()
date | open | high | close | low | pct_change | ma | std | yes_ma | yes_std | body | head | tail | body_cond | head_cond | tail_cond | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2012-01-04 | 6.64 | 6.80 | 6.40 | 6.39 | NaN | NaN | NaN | NaN | NaN | 0.24 | 0.16 | 0.01 | 0 | False | False |
1 | 2012-01-05 | 6.38 | 6.40 | 5.76 | 5.76 | -0.100000 | NaN | NaN | NaN | NaN | 0.62 | 0.02 | 0.00 | 0 | False | False |
2 | 2012-01-06 | 5.71 | 5.83 | 5.70 | 5.43 | -0.010417 | NaN | NaN | NaN | NaN | 0.01 | 0.12 | 0.27 | 1 | True | True |
3 | 2012-01-09 | 5.69 | 5.97 | 5.94 | 5.57 | 0.042105 | NaN | NaN | NaN | NaN | 0.25 | 0.03 | 0.12 | 0 | True | False |
4 | 2012-01-10 | 5.94 | 6.27 | 6.21 | 5.94 | 0.045455 | NaN | NaN | NaN | NaN | 0.27 | 0.06 | 0.00 | 0 | False | False |
判断K线形态是否符合锤子线
data['hammer'] = data[['head_cond', 'body_cond', 'tail_cond']].all(axis=1) #同时满足以上三个条件才是锤子K线;
data['hammer'].tail()
1188 False
1189 False
1190 False
1191 False
1192 False
Name: hammer, dtype: bool
data[data['hammer']].tail(10)
date | open | high | close | low | pct_change | ma | std | yes_ma | yes_std | body | head | tail | body_cond | head_cond | tail_cond | hammer | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1107 | 2016-08-24 | 12.08 | 12.09 | 12.06 | 11.99 | 0.002494 | 12.039 | 0.168091 | 12.031 | 0.168882 | 0.02 | 0.01 | 0.07 | 1 | True | True | True |
1111 | 2016-08-30 | 11.99 | 12.01 | 11.99 | 11.93 | 0.004188 | 12.038 | 0.109118 | 12.051 | 0.110499 | 0.00 | 0.02 | 0.06 | 1 | True | True | True |
1116 | 2016-09-06 | 12.29 | 12.35 | 12.34 | 12.10 | 0.007347 | 12.038 | 0.147558 | 12.007 | 0.102854 | 0.05 | 0.01 | 0.19 | 1 | True | True | True |
1129 | 2016-09-27 | 11.88 | 11.96 | 11.89 | 11.70 | -0.000840 | 12.175 | 0.166483 | 12.242 | 0.173705 | 0.01 | 0.07 | 0.18 | 1 | True | True | True |
1136 | 2016-10-13 | 12.40 | 12.40 | 12.39 | 12.27 | -0.000806 | 12.106 | 0.209772 | 12.098 | 0.198986 | 0.01 | 0.00 | 0.12 | 1 | True | True | True |
1140 | 2016-10-19 | 12.55 | 12.62 | 12.50 | 12.36 | -0.001597 | 12.294 | 0.204407 | 12.234 | 0.224311 | 0.05 | 0.07 | 0.14 | 1 | True | True | True |
1144 | 2016-10-25 | 12.59 | 12.64 | 12.61 | 12.49 | 0.000000 | 12.482 | 0.098748 | 12.449 | 0.106087 | 0.02 | 0.03 | 0.10 | 1 | True | True | True |
1145 | 2016-10-26 | 12.60 | 12.63 | 12.62 | 12.46 | 0.000793 | 12.504 | 0.102870 | 12.482 | 0.098748 | 0.02 | 0.01 | 0.14 | 1 | True | True | True |
1167 | 2016-11-25 | 13.28 | 13.36 | 13.16 | 12.91 | -0.009036 | 13.346 | 0.226137 | 13.333 | 0.241249 | 0.12 | 0.08 | 0.25 | 1 | True | True | True |
1179 | 2016-12-13 | 11.89 | 12.02 | 11.96 | 11.74 | 0.007582 | 12.556 | 0.348718 | 12.657 | 0.299742 | 0.07 | 0.06 | 0.15 | 1 | True | True | True |
由于实盘中当天的日线级别参考指标未实现,因此应根据昨日是否满足锤子形态要求作为开仓信号
data['yes_hammer'] = data['hammer'].shift(1)
2.3 编写交易逻辑——循环法
flag = 0 # 持仓记录,1代码有仓位,0代表空仓;
for i in range(2*length, len(data)): #从20天开始计算,因为前期数据无效;# 如果已持仓,判断是否止损if flag == 1:stoplose_price = max(data.loc[i, 'yes_ma'] - stoplose_trigger*data.loc[i, 'yes_std'],long_open_price-long_open_delta) # 当天价格低于止损价,则进行止损,一个是移动止损,一个是开仓时候的开仓和开仓价-1倍标准差;if data.loc[i, 'low'] < stoplose_price: #接下来要做的都是止损的操作;flag = 0
# data.loc[i, 'return'] = min(data.loc[i, 'open'], stoplose_price)/data.loc[i-1, 'close'] - 1 #计算清盘当天的收益;取min是因为,如果当天开盘价就小于了止损价,那么我们就要以开盘价就止损;#不然会导致策略收益高估;#收益计算时要除以前一天的收盘价;data.loc[i, 'return'] = stoplose_price/data.loc[i-1, 'close'] - 1 # 如果不满足止损条件,则继续持仓else:data.loc[i, 'return'] = data.loc[i, 'close']/data.loc[i-1, 'close'] - 1data.loc[i, 'trade_mark'] = 1 # 表示当天持仓# 如果未持仓,判断是否进行开仓else:# 判断是否为下降趋势,平均重心是下降的;锤子线开仓要满足形态和下降趋势;if data.loc[i-length, 'yes_ma'] > data.loc[i, 'yes_ma']:# 判断是否符合锤子形态if data.loc[i, 'yes_hammer']:# 更改持仓标记flag = 1# 记录开仓时开仓价格及标准差:是为了做固定止损;long_open_price = data.loc[i, 'open']long_open_delta = data.loc[i, 'yes_std']# 计算当天收益率data.loc[i, 'return'] = data.loc[i, 'close']/data.loc[i, 'open'] - 1 #以产生信号之后的第二天开盘价开仓;
2.4 计算策略收益率
data['return'].fillna(0, inplace=True) #对大循环中未处理的:既没有持仓,也不满足开仓条件的日期进行处理,则让这些天的return都等于0;
data['strategy_return'] = (data['return'] + 1).cumprod()
data['stock_return'] = (data['pct_change'] + 1).cumprod()
2.5 绘图
import matplotlib
import matplotlib.pyplot as plt
matplotlib.style.use('ggplot')
fig = plt.figure(figsize=(10,5))
ax = fig.add_subplot(1,1,1)
ax.plot(data.stock_return)
ax.plot(data.strategy_return)
plt.title(code)
plt.legend()
plt.show()
3. 策略改进和优化思考
- 考虑成交量的配合:在锤子线后面的一根K线如果放量的话,交易信号更可信;
- 考虑跟其他形态的结合,例如锤子线后面紧跟着一根大阳线,交易信号更可信;
- 考虑和其他技术指标的结合,配合技术指标一起进行条件选股;
金融量化-基于K线形态锤子线的趋势跟踪策略相关推荐
- 基于K线形态锤子线的趋势跟踪策略
''' 策略原理:在下跌过程中,当某一日出现锤子线,意味着当天行情先继续下跌后出现大幅反弹,行情可能由此反转;由此以观察期均线识别趋势下跌,以下跌趋势中出现锤子线作为开仓信号;采用移动止损方式进行止损 ...
- 商品期货CTA策略系列文章 -- 主流量化CTA策略之趋势跟踪策略
2016年之前,大宗商品市场一直低迷,南华商品指数年涨跌幅在2014年为-16.54%,在2015年为-14.52%,这两年间股票市场不断创造历史新高而整个商品市场却持续下跌,在2015年股市一波&q ...
- 趋势跟踪策略在专业量化交易策略中的地位
Vincent Leiberich:趋势策略简单有效.回撤有时候的确很大,但是抗一抗总能过去了.因此很多专业机构都用趋势跟踪策略.我敢说,国内"只用"趋势跟踪策略的期货私募应该一抓 ...
- python:chatGPT 写一个趋势跟踪策略 量化交易程序
chatGPT:趋势跟踪策略的量化交易程序可能会因语言和框架而异,下面是一个简单的Python代码示例,用于演示如何通过量化编程来实现趋势跟踪策略. 这段代码是一个简单的策略实现,它读取股票数据并计算 ...
- 股票个人量化交易接口最常见的趋势跟踪策略
趋势跟踪策略相对于高频策略和统计套利类的策略来说风险就相对较大了,这是因为该策略风险敞口暴露较多. 我们在市面上常见的比如Smart Beta策略,CTA趋势跟踪策略和股票指数增强都是属于这种风险敞口 ...
- 菜鸟de量化之路——(1)趋势跟踪策略
这是我第一篇博客,也是我的本科毕业课题--开发一个简易的量化系统,包括择时选股模块和回测模块. 所谓的量化系统,是指以数学模型代替人为判断,以程序交易替代人为操作,利用计算机的庞大的计算能力,制定能带 ...
- 锤子位置服务器,重要的反转形态:锤子线及上吊线
锤子线和上吊线都是K线形态分析中重要的反转形态.它们有两种颜色,可以是阳线也可以是阴线,也就是无论是涨或跌都可以形成锤子线或上吊线.它最明显的特真就是有较长的下影线,实体较小并处于K线图的顶端位置,一 ...
- python 移动平均线_6移动平均线预测交易
清华编程高手尹成带你基于算法实践python量化交易 量化交易是指以先进的数学模型替代人为的主观判断,利用计算机技术从庞大的历史数据中海选能带来超额收益的多种"大概率"事件以制定策 ...
- AlphaMind:趋势跟踪及量化交易系统
合约1+1第三期直播正式开始前我们先热烈欢迎今天主讲的第一位老师AlphaMind 首先介绍一下AlphaMind(A神):全自动量化趋势交易员,合约帝实盘收益超250万,琅琊榜第一期榜首-Alpha ...
最新文章
- Intellij Idea/Webstorm/Phpstorm 的高效快捷键
- zigbee的路由器能分配网络地址吗_网络基础知识学习 小白也能变专家
- 《Unity 3.x游戏开发实例》——2.10节注意
- mysql编译方式安装_mysql编译方式安装
- gvim文本编辑器帮助_如何帮助您的文本编辑器帮助您
- 超级警探大战悍匪2java_JavaWeb之会话技术
- 讲座:数据库项目生命周期中的优化 讲稿下载
- 信息系统项目管理03——项目立项管理
- 苹果笔记本安装Win10双系统+分区教程《完整精华版》
- 2015腾讯校园招聘软件测试部分笔试题
- 国内主流虚拟化厂商之间比较
- 国标 计算机房 湿度,数据中心机房:温度、湿度标准是什么?
- 这个时代“寒门再难出贵子” (转帖)
- 第七章 项目招投标与合同管理
- 浏览器火狐3.0发布之盛况
- 让玩家提升游戏耐玩度的8个小技巧
- linux cat和vim区别,cat命令和vim存在着什么区别
- Codechef June Challenge 2020 简要题解
- android 经纬度 转换成地址,Android 百度地图经纬度转换成地址
- java计算身体质量指数
热门文章
- 两个L组成的括号?(取整符号)
- Spring学习笔记(完结)
- 使用print时出错 SyntaxError: Missing parentheses in call to ‘print‘ Did you mean print(““)
- U盘重装系统-非常简单制作方法
- JVM--查看堆栈信息
- Markdown 教程: 1 数学公式和特殊符号
- java se和java_Java SE 9非常适合灵活,可扩展和无服务器的未来
- 不重装系统,如何将系统从SSD迁移到M2固态硬盘
- 计算机工程 文章没有创新,浅谈计算机教学学生创新能力培养-计算机工程论文-计算机论文(8页)-原创力文档...
- 毕业设计-基于深度学习的图像隐写分析