本文旨在策略学习探讨,不构成任何投资建议!

之前我们用两篇文章将账户和交易封装,做了一定准备工作。今天,将正式开启对策略的考核。

对于券商、钢铁、有色、甚至房地产等右侧行情的行业,通常会用到一个方法——右侧追击,也就是所谓的追涨杀跌。

中心思想基本是以较低的试错成本,一次次的去追击它们的强势行情。中间可能会有多次追击失败,但亏损不会太大,而一旦追击成功,收益相对而言都较为可观。

本次以A股东方财富历史数据为示例,股票代码300059

1. 数据获取

其中quan_trade是在交易封装中封装好的类

# 导入相关库
import akshare as ak
import pandas as pd
import quan_trade # 导入交易类
### 获取东方财富历史行情数据
# 参数adjust:默认返回不复权的数据; qfq: 返回前复权后的数据; hfq: 返回后复权后的数据。
# 该股票涉及到多次转增分红,这里需要选择前复权
dfcf_df = ak.stock_zh_a_hist(symbol='300059', period="daily", start_date="20011101", end_date='20221231', adjust="qfq")
dfcf_df

该股票于2010-03-19上市,截止2022-04-08,一共有2865条数据。

2.策略更新

策略之前封装到了quan_trade.py中的类Trade中,添加右侧追击策略只需在类中添加新方法,然后在主函数self.main中添加策略判断即可。

先来梳理一下右侧追击的策略:

1. 将资金分为5份;

2. 突破新高买入一份,止损点设为买入价下方8%;

3. 每涨10%,追加一份,并将止损点更新为最新买入价下方8%;

4. 一旦期间触发止损,意味着此次追击失败,再觅良机重新追击;

5. 如果5份全部买入完成,设最高价下方8%为动态止盈点,一旦触发止盈,意味着本次追击成功且圆满结束。

右侧追击中,会有不少假突破。可能会对本金造成侵蚀,但这是右侧交易必要的磨损。只要严格遵守纪律,在止损点果断斩仓,风险就是可控的。

接下来,就是要将我们的策略告诉程序,在此之前有几个细节需要确定:

1. 新高为半年内新高(即前180个交易日的最高价,非最高收盘价)

2. 突破新高是指当日收盘价站上前期高点,非当日最高价破新高。避免上长影线触发策略买入(上长影线意味着抛压巨大,不是很好的追击点)

3. 每次交易以当日收盘价作为交易价格,更为贴近在现实中能买到或卖到的价格

代码如下:

# 在quan_trade.py文件的的类Trade中添加此方法
def by_right_attack(self):"""右侧追击"""# 定义两个变量,分别存放前高以及追击完成后的最高股价last_higt = max_price = Nonefor i in range(180, self.data.shape[0]):# 更新前半年最高价last_higt = self.data['最高'][i-180:i].max()# 无持仓(持仓数据为空或者持仓数量为零)if self.account.position.empty or self.account.position.iloc[-1].amount == 0:# 价格未突破if self.data.iloc[i].收盘 <= last_higt:self.account.no_trade_update_asset(self.data.iloc[i].日期, self.symbol, self.data.iloc[i].收盘)continue# 破新高买入elif self.account.asset.iloc[-1].cash >= self.data.iloc[i].收盘 * self.trade_amount :self.account.trade_update(self.data.iloc[i].日期,'B',self.symbol,self.trade_amount,self.data.iloc[i].收盘)# 有持仓else:# 追击小于等于4次if self.account.position.iloc[-1].amount <= 4 * self.trade_amount:# 跌破8%,止损if self.data.iloc[i].收盘 <= self.account.order.iloc[-1].trade_price * 0.92 :self.account.trade_update(self.data.iloc[i].日期,'S',self.symbol,self.account.position[self.account.position['symbol'] == self.symbol].iloc[-1].amount,self.data.iloc[i].收盘)# 上涨10%,追击elif self.data.iloc[i].收盘 >= self.account.order.iloc[-1].trade_price * 1.1 and (self.account.asset.iloc[-1].cash >= self.data.iloc[i].收盘 * self.trade_amount):self.account.trade_update(self.data.iloc[i].日期,'B',self.symbol,self.trade_amount,self.data.iloc[i].收盘)# 右侧追击完成,设止盈保护else:# 更新最高点(从最后一次买入后开始计算)max_price = self.account.order.iloc[-1].trade_priceif self.data.iloc[i]['最高'] > max_price :max_price = self.data.iloc[i]['最高']# 最高点下跌8% 止盈if self.data.iloc[i]['收盘'] <= max_price * 0.92 :self.account.trade_update(self.data.iloc[i].日期,'S',self.symbol,self.account.position[self.account.position['symbol'] == self.symbol].iloc[-1].amount,self.data.iloc[i].收盘)
# 在类Trade的self.main中添加策略判断
def main(self):#选择交易策略if self.trade_strategy == 'boll' :self.by_boll()# 新添加的策略——右侧出击elif self.trade_strategy == 'right_attack':self.by_right_attack()else :pass

3.数据回测

回顾一下策略:将资金分为5份,每次买的话买入一份,卖的话清仓。

在我们封装好的账户中,必须一次性丢给它本金多少,然后跑出来3个DataFrame数据——收益详情、持仓详情、订单记录。

很显然,无法满足将资金分为5份的个性化需求。不过,其中最关键的是什么?是找到每个买点和卖点,有了他们。不管资金怎么分配,也很容易算出收益变化。

而账户中的订单记录,正好记录了每次的买点和卖点。

创建交易对象需传入的参数中,交易数量trade_amount定为每次100;本金可适量的设定大一些,这里设定为100w,防止出现买入机会而本金不够的情况。

## 创建交易对象,调用主函数main
trade = quan_trade.Trade('300059', dfcf_df, 'right_attack', 100 , 1000000)
trade.main()# 查看订单记录
trade.account.order

一共发生了68次交易记录,根据该订单记录,可以很轻松得到资金分为5份追击后的情况。

这里本金设定为10w,每次追击买入2w。(这里忽略A股最小不可分割单位为100股的限制)

创建一个DataFrame数据用来存放每次出击的账户收益情况,包含的内容有:

  • start_time :第一次买入时间

  • end_time :清仓时间

  • capital:本金

  • attack_times:追击次数

  • profit:盈亏

  • profit_rate:持仓收益率(分母只算被最大占用的资金)

  • total_profit_rate:总收益率(分母为本金)

代码如下:

# 创建profit_df用来存放每次追击的情况
profit_df = pd.DataFrame(columns = ['start_time','end_time', 'capital', 'attack_times', 'profit', 'profit_rate','total_profit_rate'])
# 初始化部分数据
start_time = None
capital = 100000
attack_times = 0
profit = 0
amount = 0 # 记录每次追击累积交易的数量
# 遍历订单记录,计算每次追击后的数据,存放到profit_df
for i in range(0,trade.account.order.shape[0]):if trade.account.order.iloc[i]['trade_type'] == 'B':# 记录每次追击开始的时间if attack_times == 0:start_time = trade.account.order['date'].iloc[i]#计算累计追击次数以及累计买入数量attack_times += 1amount += capital / 5 / trade.account.order.iloc[i]['trade_price']else :# 数据存放profit_df = profit_df.append({'start_time':start_time,'end_time':trade.account.order['date'].iloc[i], 'capital':capital,'attack_times':attack_times, 'profit': trade.account.order.iloc[i]['trade_price'] * amount - capital / 5 * attack_times, 'profit_rate': (trade.account.order.iloc[i]['trade_price'] * amount /(capital / 5 * attack_times) - 1) * 100,'total_profit_rate':(trade.account.order.iloc[i]['trade_price'] * amount - capital / 5 * attack_times) / capital * 100},ignore_index=True)# 卖出意味着本次追击结束,清零attack_times = amount = 0 

4.收益分析

# 总收益及追击明细
print("收益合计:",profit_df.profit.sum())
profit_df # 字段意义见上方文字

可以看到,从该只股票2010-03-19上市以来,一共出现了20次右侧追击的机会,成功将子弹打完的一共有3次(追击次数attack_times为5)。成功率一般,这也是策略还可以优化的地方。后期我们可以在买入时加些条件限制,比如顾比均线趋势、放量情况等,让程序尽可能识别假突破,减少本金磨损。

总体取得了超过12w的收益。按10w的本金来算,即便追击失败,单次最大的亏损也只有3.25%,而追击成功后最大一次收益达到了81.3%。

整体来看,策略表现还不错。风险可控,并且收益可观。

或许有人会觉得,策略持续了长达12年的时间,取得122.87%回报(这里忽略掉因追击失败亏损后需填补的少量资金,实际上本金会略大于10w),折合年化也就6.9%,并没有很惊艳。但12年时间里,绝大部分时间里现金都是躺在账户里的,真正被占用的时间加起来还不到一年半。其它时间资金都是活动的,可以躺在货币基金里吃利息,也可以去投资别的标的。不到一年半资金占用时间,对应超过120%收益,这样想想是不是就变得惊艳了。

但是,事情真的这么简单吗?

其实一直以来都忽略了一个问题,也是大A独有的特色——涨跌停。强势行情中有可能开盘直接涨停,导致该买入时没有卖盘,压根就买不进去。我们拿2015-04-17到2015-05-04期间的交易来看,这次追击看上去很完美。创造了8w多的利润,也占了总收益12w多的大头。可现实真的有这么顺利吗?

从上图可以看出,东方财富从2015年4月16号就开启了连续的涨停行情,持续了11天。除去最后两天能买进去,前面9个交易日都是一字涨停,是没有买入机会的。而策略在4月17开启了追击,连续5天在相对低位买进,然后在5月4号的高位清仓。这显然与现实不符,现实中压根一次都买不进去。所以此次8w多的利润不过是水中花,镜中月。

如果眼睁睁的看着它涨,实在痛苦。也可以选择启用备用方案,用相关性较高的标的来替代,比如券商ETF(512000),同样的策略,买入同样的资金。不过是否能对收益产生正向助力,有待考证。

我们的重心还是放在单个标的收益回测,这里就不考虑备用方案启动后的收益变化了。

另外,除了一字涨停外,还要考虑止损时有没有一字跌停的情况出现。一字跌停后,会止损在更低的位置,增大亏损。

5.真实收益分析

5.1 真实的数据回测

Trade类中有一个参数max_volatility,默认值为None,意味着默认没有涨跌幅限制。像港股、美股、数字货币、期货等都不需要传递此参数。而A股主板每天有10%的涨跌额限制,所以需将数字10传递给它。另外,在Trade类的by_right_attack方法中,添加一个条件判断。

那么程序会在交易中自动判断是否有一字涨停或跌停,如果有,则不会交易。

### 在quan_trade.py文件的的类Trade中微调by_right_attack方法
def by_right_attack(self):"""右侧追击"""# 定义两个变量,分别存放前高以及追击完成后的最高股价last_higt = max_price = Nonefor i in range(180, self.data.shape[0]):### 												

右侧追击(一)——东方财富相关推荐

  1. 右侧追击(二)——券商行业

    在上文中用东方财富的历史数据,回测了右侧出击策略的表现.资金占用时间不到一年半,对应40%的收益,表现基本让人满意.不过仅凭一只股票的收益表现,偶然性太高,很难说明策略的可靠度. 本次我们拿证券公司( ...

  2. 右侧追击(三)——策略优化

    前文数据表明,右侧追击确实是抓取券商强势行情的一把利器.不过策略也有一个明显的弊端,也是有待优化的地方--追击成功率.从整个券商行业来看,10次追击,都未必有一次成功.在实战中,每一次失败,不仅意味着 ...

  3. mac桌面壁纸_在Mac上从命令行设置桌面墙纸

    mac桌面壁纸 Whenever I need to accomplish a basic task that typically calls for interacting with a UI, I ...

  4. 音视频开发——音视频学习资料

    目录 1.为什么要学习音视频? 2.如何学习系统性音视频? 3.音视频相关的资料 最近有朋友问想学习音视频,应该怎么学,有什么资料吗? 这个问题也困扰我很久,几年前就想开始音视频相关的学习,但是一直找 ...

  5. 音视频开发之旅(32)-音视频学习资料

    目录 为什么要学习音视频? 如何学习系统性音视频? 音视频相关的资料 学习实践的输出文章分类聚合 收获 最近有朋友问想学习音视频,应该怎么学,有什么资料吗? 这个问题也困扰我很久,几年前就想开始音视频 ...

  6. python爬取东方财富网资金流向数据(在本地生成csv文件)

    今天我们来试着用python爬取东方财富网资金流向的表格数据. 第一步:程序及应用的准备 首先我们需要安装selenium库,使用命令pip install selenium;然后我们需要下载对应的c ...

  7. Python爬虫(6):比Selenium快100倍的方法爬东方财富网财务报表

    博客原文来自我的博客:https://www.makcyun.top/web_scraping_withpython6.html 摘要: 上一篇文章,我们用Selenium成功爬取了东方财富网的财务报 ...

  8. 前嗅教你大数据:采集东方财富网数据

     l 采集场景 [场景描述]采集东方财富网行情中心沪深京A股数据. [使用工具]前嗅ForeSpider数据采集系统,免费下载: ForeSpider免费版本下载地址 l采集网站 [入口网址] htt ...

  9. 比Selenium快100倍的方法爬东方财富网财务报表

    之前,我们用Selenium成功爬取了东方财富网的财务报表数据,但是速度非常慢,爬取70页需要好几十分钟.为了加快速度,本文分析网页JavaScript请求,找到数据接口然后快速爬取财务报表数据. 1 ...

最新文章

  1. 某程序员感叹自己学历虽低,却能进入阿里!虽然只是p6,却面过不少清北毕业生!清北毕业生也没什么了不起,水货一抓一大把!...
  2. R语言应用calibrate包的textxy函数向R原生绘图结果中添加文本标签:添加多个文本标签、改变文本标签的字体、改变文本标签的字体颜色
  3. poj 3007 Organize Your Train part II (哈希)
  4. PCM复用设备主要传输什么业务?
  5. 鳗鱼刺多怎么处理图像_怎么在做鱼前去除鳗鱼刺?
  6. 你可能不需要 jQuery!使用原生 JavaScript 进行开发
  7. js 字符串转换成数字(转)
  8. 拓扑容差如何修改_如何做到全屋WIFI无死角,MESH组网对比有哪些优势?
  9. Scrapy框架高级操作
  10. 机器学习霸占高薪榜、区块链偃旗息鼓?2020 年软件工程师状况解读!
  11. 无法装载这个对象_面试官:别的我不管,这个JVM虚拟机内存模型你必须知道
  12. autojs遍历当前页面所有控件_伙伴系统:页面分配器
  13. 尚学堂视频笔记一:java面向对象基础和java基础知识
  14. 置信区间的临界值_在用正态分布进行置信区间估计时,临界值2.58所对应的置信水平是( )。...
  15. swagger文档增强工具knife4j使用详解
  16. 《 线性代数及其应用 (原书第4版)》——1.5 线性方程组的解集
  17. 区块链让公益更透明安心 | FinTechathon 上园村小红果团队
  18. 再也不要相信你的眼睛:步步逼近的AI换脸术
  19. Python错误集锦:打开文件路径提示参数无效,OSError: [Errno 22] Invalid argument: ‘D:\juzicode\桔子code\readme.txt’
  20. 手动查找 IAT 的方法!!!

热门文章

  1. sublime的一些使用技巧
  2. 粒子滤波实现刀具寿命预测
  3. objective-c复制
  4. (附源码)ssm高校志愿者服务系统 毕业设计 011648
  5. 综合评价方法(一)------基础知识
  6. 什么是BFC?以及形成BFC的条件
  7. Android 报错A/libc: Fatal signal 6 (SIGABRT), code -6 in tid *** 解决
  8. linux内核-系统调用execve()
  9. 千亿元宇宙市场,Soul、映客的新动力
  10. 测试环境部署——selenium+python