学习笔记
OHLCSTX.run生成各类退出信号
退出信号:
平仓(卖出)的方式,最简单的,相对买入价的固定比例止损,
止损:比如,相比买入价下跌10%就卖出。
跟踪止损:相比持有期间的最高价,下跌10%就卖出。
止盈:比如,相比买入价,上涨达到10%就卖出,落袋为安。
超时退出:买入最多持有10天,10天到期后强制卖出。
以上退出信号未必100%达成(触发),如果价格波动非常小,有可能一直不会被触发,退化为持续持有策略。
稍微复杂的是OHLCSTX相关代码
先参考官方文档中关于:OHLCSTX的内容:https://vectorbt.dev/api/signals/generators/#vectorbt.signals.generators.OHLCSTX
函数原型
1 |
|
参考官方demo简单分析下
1 |
|
参考上面含义解析,理解下面的信号结果output
直角方块:固定止损0.1,close=10,止损价9,所以最终退出价格为9,原因为止损退出
椭圆部分:跟踪止损0.1,high=13,止损价11.7,所以最终退出价格为11.7,原因为跟踪止损退出
圆角方框:无止损,止盈价10*1.1=11,所以最终退出价格为11,原因止盈退出
1 | sl_exits = vbt.OHLCSTX.run( |
不同方式的退出信号达成率
信号达成率:退出是否被触发,比如止损5%,但是行情一直1%内波动,则信号不会被触发。
继续分析如下代码块
1 | print(pd.Series({ |
以 ‘Stop Loss’: sl_exits.vbt.signals.total().groupby(‘stop_value’).mean(),为例.
sl_exits退出方式下,stop_value从0.01->0.99不同取值下,对应的,达成率
所以:随着stop_value从小到大,分别意味着价格要下探到0.99,0.98 -> 0.01才能触发信号止损,故越靠右侧,曲线越接近与0
takeProfit线,就更明显了,止盈取值遇到,信号达成率越低。
merge期末强制退出信号
持有到期后(最后一天),生成卖出信号,强制卖出。
1 | sl_exits.iloc[-1, :] = True # 强制周期末尾退出信号为True,所以可能存在2个True情况 |
持有到期hold_exits,随机退出rand_exits
1 | hold_exits = pd.DataFrame.vbt.signals.empty_like(sl_exits) |
退出信号融合到columns.multiIndex
1 |
|
各退出方式,退出价对应持仓周期
1 | avg_distance = entries.vbt.signals.between_ranges(other=exits)\ |
关于between_ranges,参考:https://vectorbt.dev/api/signals/accessors/#vectorbt.signals.accessors.SignalsAccessor.between_ranges
对于单列比对
对于2列比对
可视化
1 | avg_distance[exit_types].vbt.plot( |
可见随机类型的平均持仓周期约为100,符合理论,随着Stop value的增大,持仓周期增大,意味着价格条件越苛刻,满足条件的标的越少,符合直观理解。
各退出类型对应的收益率
1 | # del pf |
绘制特定类型的收益率分布
1 | total_return_by_type = total_return.unstack(level='exit_type')[exit_types] |
1 | print(total_return_by_type['Holding'].describe(percentiles=[])) |
由于这个数据是stopvalue止损价从0.01->0.99的总体统计,感觉说明不了什么。
各退出方式收益率分位图
1 | print(pd.DataFrame({ |
各退出方式胜率
1 | print((total_return_by_type > 0).mean().rename('win_rate')) |
不同止损方式在不同止损价位上的预期收益(期望收益)
1 | init_cash = vbt.settings.portfolio['init_cash'] |
这张图没太理解,从代码中的公式上看
图中y轴:胜率*平均收益-亏损概率*平均亏损 = 期望收益
但是随着stopvalue的上涨,期望收益不断靠近达到10? 这一点不是很理解
看不懂todo
后面一部分看不懂了,暂时跳过吧,把图示截图出来
1 | return_values = np.sort(total_return_by_type['Holding'].values) |
交互式图表
1 | range_starts = pd.DatetimeIndex(list(map(lambda x: x[0], split_indexes))) |
1 | dashboard.close() |