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

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

本次我们拿证券公司(399975)成分股中的所有证券公司,一共49家来代表券商行业、再选定2012-01-01至今作为时间区间来做数据回测,基本上就能评判出策略在券商行业中的综合实力。

1.股票代码预览

首先需要知道,一共是哪些券商公司,它们的代码分别是多少?写了个小爬虫程序,在某行情网站中抓取到了我们的目标券商公司股票代码,然后保存到本地csv文件(爬虫过程及源码这里不做展示)。

先将所有券商的代码及公司读取出来,如下:

# 导入相关库
import akshare as ak
import pandas as pd
import quan_trade # 交易类
import time

# 从本地读取所有券商股票代码
dealer_df = pd.read_csv('dealer_data/symbols.csv',dtype = {'symbol':str})
# 展示前5条
dealer_df.head()

2. 函数封装

右侧追击(一)——东方财富中我们对单只股票每次追击情况进行了统计。本次涉及到49支股票,还需要将每只股票的多次追击详情汇总。

定义一个函数,需传入的参数有order——订单记录,symbol——股票代码,begin_date——该股票具备行情数据的起始日期,capital——本金(每次买卖为本金的1/5,默认值为100000)。在函数内部计算出两个DataFrame数据返回,profit_df记录单只股票每次追击的情况,summary_df对该股票多次追击详情进行汇总,代码如下:

def get_profit(order,symbol,begin_date,capital = 100000):
    # 创建profit_df用来存放每次追击的情况, summary_df存放每只股票的追击汇总
    profit_df = pd.DataFrame(
        columns = ['symbol','start_time','end_time', 'capital', 'attack_times', 'profit', 'profit_rate','total_profit_rate'])
    summary_df = pd.DataFrame(columns = [
        '跟踪起始时间','代码','公司','本金','总追击次数','成功次数','追击成功率','单次最大亏损','单次最大盈利','总利润','资金占用时间/天','折合年化'
    ])
    # 订单记录为空,直接返回
    if order.empty:
        print(symbol, ": 订单记录为空")
        return profit_df,summary_df
    # 初始化部分数据
    start_time = None
    attack_times = 0
    profit = 0
    amount = 0 # 记录每次追击累积交易的数量
    # 遍历订单记录,计算每次追击后的数据,存放到profit_df
    for i in range(0,order.shape[0]):
        if order.iloc[i]['trade_type'] == 'B':
            # 记录每次追击开始的时间
            if attack_times == 0:
                start_time = order['date'].iloc[i]
            #计算累计追击次数以及累计买入数量
            attack_times += 1
            amount += capital / 5 / order.iloc[i]['trade_price']
        else :
            # 数据存放
            profit_df = profit_df.append({
                'symbol':symbol,
                'start_time':start_time,
                'end_time':order['date'].iloc[i], 
                'capital':capital,
                'attack_times':attack_times, 
                'profit': order.iloc[i]['trade_price'] * amount - capital / 5 * attack_times, 
                'profit_rate': (order.iloc[i]['trade_price'] * amount /(capital / 5 * attack_times) - 1) * 100,
                'total_profit_rate':(order.iloc[i]['trade_price'] * amount - capital / 5 * attack_times) / capital * 100
            },ignore_index=True)
            # 卖出意味着本次追击结束,清零
            attack_times = amount = 0 
    ### 追击详情汇总
    summary_df = pd.DataFrame({
        '跟踪起始时间':begin_date,
        '代码':symbol,
        '公司': dealer_df[dealer_df['symbol'] == symbol].company,
        '本金': capital,
        '总追击次数' : profit_df['attack_times'].count(),
        '成功次数': profit_df[profit_df['attack_times'] == 5].attack_times.count(),
        '追击成功率':profit_df[profit_df['attack_times'] == 5].attack_times.count() / profit_df['attack_times'].count() * 100,
        '单次最大亏损':profit_df['profit'].min(),
        '单次最大盈利':profit_df['profit'].max(),
        '总利润':profit_df['profit'].sum(),
        '资金占用时间/天':(profit_df['end_time'] - profit_df['start_time']).dt.days.sum() + profit_df.start_time.count(),
        '折合年化':((profit_df['profit'].sum() /capital + 1) ** (365 / ((profit_df['end_time'] - profit_df['start_time']).dt.days.sum() + profit_df.start_time.count())) -1) * 100
    })
    return profit_df, summary_df

函数get_profit的使用,拿东方财富为例:

df = ak.stock_zh_a_hist(symbol='300059', period="daily", start_date="20120101", end_date='20221231', adjust="qfq")
trade = quan_trade.Trade('300059', df, 'right_attack', 100 , 1000000, max_volatility = 10)
trade.main()
profit_df, summary_df = get_profit(trade.account.order, '300059', trade.data.iloc[0].日期)
# 查看每次追击情况
profit_df

# 查看汇总
summary_df

profit_df几乎就是我们在上一篇中所用到的数据,记录了对应股票每次追击情况;summary_df是对profit_df中数据的汇总,里边还计算出了对应股票右侧追击的折合年化回报。

3.计算每只股票的追击汇总

将49支股票的追击详情及汇总分别放到一个DateFrame中,基本上能看出来策略在券商行业中的整体表现了

# 记录程序运行开始时间
start = time.time()
# 定义变量存放所有股票的追击详情以及每只股票的追击汇总
dealer_profit_df = pd.DataFrame()
dealer_total_profit_df = pd.DataFrame()
# 遍历dealer_df取出所有股票代码
for symbol in dealer_df['symbol']:
    # 回测区间范围设定从2012年开始,截止到现在
    df = ak.stock_zh_a_hist(symbol= symbol, period="daily", start_date="20120101", end_date='20221231', adjust="qfq")
    trade = quan_trade.Trade(symbol, df, 'right_attack', 100 , 1000000, max_volatility = 10)
    trade.main()
    profit_df, summary_df = get_profit(trade.account.order, symbol, trade.data.iloc[0].日期)
    # 将每只股票追击详情及汇总分别添加到dealer_profit_df,dealer_total_profit_df
    dealer_profit_df = dealer_profit_df.append(profit_df)
    dealer_total_profit_df = dealer_total_profit_df.append(summary_df)

print("程序运行时间/min: ",(time.time() - start)/60 )

上面的代码涉及到一定数量的运算,会耗费一点时间。一共有6支股票没有订单记录,股票代码打印在了上面。也就是说在它们上面没有找到任何参与机会。经过简单的分析就可以知道,这些股票都是在最近两三年内上市,策略还需要有大半年的缓冲期(需跟踪180个交易日内的最高价),跟踪周期较短,没有参与机会也很正常。

# 查看所有股票的追击详情
dealer_profit_df

# 查看所有股票的追击汇总前5条
dealer_total_profit_df.head()

策略从2012-01-01开始追踪,其后的第一个交易日是2012-01-04,但dealer_total_profit_df中的起始跟踪时间有一些会晚于这个时间,那是因为它们直到这个起始跟踪时间点才上市挂牌交易。

根据追击汇总dealer_total_profit_df计算策略在券商行业中的平均收益

# 对所有股票追击汇总再汇总
avg_profit_df = pd.DataFrame({
    '参与股票数量':dealer_total_profit_df.shape[0],
    '盈利数量':dealer_total_profit_df[dealer_total_profit_df['总利润'] > 0].shape[0],
    '亏损数量':dealer_total_profit_df[dealer_total_profit_df['总利润'] <= 0].shape[0],
    '追击成功率':100 * dealer_total_profit_df['成功次数'].sum() / dealer_total_profit_df['总追击次数'].sum(),
    '单支股票最大利润':dealer_total_profit_df['总利润'].max(),
    '单支股票最大亏损':dealer_total_profit_df['总利润'].min(),
    '平均收益':dealer_total_profit_df['总利润'].mean(),
    '平均年化回报':dealer_total_profit_df['折合年化'].mean()
},index = [0])
avg_profit_df

4.结论分析

收益总览

一共参与了43支股票,追击成功率8.63%,平均收益2.8w,对应平均年化回报49.42%,整体还不错。

其中盈利的有25支,取得最大利润的是光大证券,18.8w。该股票追击了7次,就有2次追击成功。28%的成功率极大的拉高了收益,按171天的资金占用时间来计算,折合年化高达856.62%。

亏损数量为18支,踩坑的概率还是有一些的。创造最大亏损是国投资本,超过了1.8w。8次追击,0次成功。对应10w的本金,摩擦成本高达18%,风险也不容小觑。


利润周期

# 摘取追击成功的追击详情
dealer_profit_df[dealer_profit_df['attack_times'] == 5].sort_values(by='start_time')

看利润分布,绝大部分的收益都是2014第4季度创造的,追击成功的时间区间大部分也集中于此。

翻看证券公司(399975)的周线图,在我们跟踪的十年期间,2014年尾部也是其表现最为疯狂的时期,从10月份600点左右一路飙升,到12月下旬时涨到了第一个高点1500点左右,这一波所有股票加在一起吃到了接近120万的利润,极大的拉高了平均收益。随后在2015年2季度再创新高,同样也吃到了一小部分利润,相较而言其它时间段都没有特别突出的表现。

再往前看,2007年有类似行情,如果策略跟踪到2007年,收益应该还能再创辉煌。这里单纯意淫一下,2007年中到2014下旬花了7年多的时间,2014年底到现在也是7年多,券商行业是否又在酝酿一次大腾飞呢?

亏损分析

# 查看所有亏损股票的追击总览
dealer_total_profit_df[dealer_total_profit_df['总利润'] <= 0]

18支亏损的股票中,它们的追击成功次数全部为0。换句话说,只要有一次追击成功,没有一只股票是亏损的。

不过也并非所有成功次数为0的股票,都会亏损。比如国信、西南、哈投,它们都创造了正收益。其实只要策略在开启追击后,能连续买到第3、4次,就有很大机会创造正收益!

# 追击成功次数为0且利润为正的股票记录
dealer_total_profit_df[dealer_total_profit_df['总利润'] > 0 ][dealer_total_profit_df['成功次数'] == 0]

另外可以看到,所有亏损的股票中,除了国投和国海,其它的上市时间都晚于2014年,错过了券商行业最疯狂的黄金时段。乐观的看,如果未来再有这么一波强势行情,它们中的绝大部分是不是都能收回摩擦成本,并跑出可观的正收益?这个有待时间给我们答案!

# 国海证券的每次追击详情
dealer_profit_df[dealer_profit_df['symbol'] == '000750']

# 国投证券的每次追击详情
dealer_profit_df[dealer_profit_df['symbol'] == '600061']

国海和国投对于策略而言,彻底就是个坑了。即便在2014年底遍地捡黄金的时代,二者也没有完成一次完整的追击。

所以即便是券商这种反身性行业、严格遵守右侧追击制度、在整个行业疯狂上涨的3层buff加持下,追击个股也有踩坑的风险!国海和国投就是血淋淋的教训,把资金丢到它们身上,就等同于从枪林弹雨般的黄金中完美的躲了过去!

总结

  1. 平均年化回报达到49.42%,整体表现不错;

  2. 追击成功率8.63%,策略有待优化提高成功率;

  3. 绝大部分利润都贡献于2014年年底的行情,右侧追击博的就是这种机会;

  4. 虽然券商这种行业适合右侧追击,但追击个股依然有踩坑的风险。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值