LOADING
1399 字
7 分钟
vectorbt学习_50DMA之十过滤器

策略研发过程中,除了纯粹的买卖技术指标之外,还有一类信号用于判断当前行情是否应该入场。
比如:大盘或个股持续处于波动性中,没有明显方向性,拉锯状态,此时大多数趋势类策略都会反复开仓,止损,开仓,止损,导致稳定的小额亏损。

01,基础配置信息#

#conda envs:vectorbt_env
import warnings
import vectorbt as vbt
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
import pytz
from dateutil.parser import parse
import ipywidgets as widgets
from copy import deepcopy
from tqdm import tqdm
import imageio
from IPython import display
import plotly.graph_objects as go
import itertools
import dateparser
import gc
import math
from tools import dbtools
warnings.filterwarnings("ignore")
pd.set_option('display.max_rows',500)
pd.set_option('display.max_columns',500)
pd.set_option('display.width',1000)

02,行情获取和可视化#

a,时间交易参数配置#

# Enter your parameters here
seed = 42
symbol = '002594.XSHE'
metric = 'total_return'
start_date = datetime(2020, 1, 1, tzinfo=pytz.utc) # time period for analysis, must be timezone-aware
end_date = datetime(2023,1,1, tzinfo=pytz.utc)
time_buffer = timedelta(days=100) # buffer before to pre-calculate SMA/EMA, best to set to max window
freq = '1D'
vbt.settings.portfolio['init_cash'] = 10000. # 100$
vbt.settings.portfolio['fees'] = 0.0025 # 0.25%
vbt.settings.portfolio['slippage'] = 0.0025 # 0.25%

b,获取行情和行情mask#

# Download data with time buffer
cols = ['Open', 'High', 'Low', 'Close', 'Volume']
# ohlcv_wbuf = vbt.YFData.download(symbol, start=start_date-time_buffer, end=end_date).get(cols)
ohlcv_wbuf=dbtools.MySQLData.download(symbol).get() # 自带工具类查询
assert(~ohlcv_wbuf.empty)
ohlcv_wbuf = ohlcv_wbuf.astype(np.float64)
print("ohlcv_wbuf.shape:",ohlcv_wbuf.shape)
print("ohlcv_wbuf.columns:",ohlcv_wbuf.columns)
# Create a copy of data without time buffer
wobuf_mask = (ohlcv_wbuf.index >= start_date) & (ohlcv_wbuf.index <= end_date) # mask without buffer
ohlcv = ohlcv_wbuf.loc[wobuf_mask, :]
print("ohlcv.shape:",ohlcv.shape)
# Plot the OHLC data
ohlcv.vbt.ohlcv.plot().show_svg() # 绘制蜡烛图
# remove show_svg() to display interactive chart!
ohlcv_wbuf.shape: (978, 5)
ohlcv_wbuf.columns: Index(['Open', 'High', 'Low', 'Close', 'Volume'], dtype='object')
ohlcv.shape: (728, 5)

svg

03,朴素std,stdma#

最简单的过滤方法是计算std,然后再计算标准差的ma,当std>ma(std),说明波动增大,反之波动减小。趋势策略当std>ma(std)时才开仓
大致效果如下

import plotly.graph_objects as go
from plotly.subplots import make_subplots
# 计算收盘价的标准差
std_close_wbuf = ohlcv_wbuf['Close'].rolling(window=20).std()
# 计算标准差的移动平均
std_close_ma_wbuf = std_close_wbuf.rolling(window=20).mean()
std_close=std_close_wbuf[wobuf_mask]
std_close_ma=std_close_ma_wbuf[wobuf_mask]
# 创建一个子图布局:2行1列
fig = make_subplots(rows=4, cols=1, shared_xaxes=True, vertical_spacing=0.02)
# 第一行添加蜡烛图
ohlcv_fig = ohlcv[['Open', 'High', 'Low', 'Close', 'Volume']].vbt.ohlcv.plot()
fig.add_trace(ohlcv_fig.data[0], row=1, col=1) # 添加蜡烛图数据
fig.add_trace(ohlcv_fig.data[1], row=2, col=1) # 添加交易量柱状图
# 第二行添加两个移动平均线
fig.add_trace(go.Scatter(x=ohlcv.index, y=std_close, mode='lines', name='SMA 20'), row=3, col=1)
fig.add_trace(go.Scatter(x=ohlcv.index, y=std_close_ma, mode='lines', name='SMA 50'), row=3, col=1)
# 创建条件指标
std_indicator = (std_close > std_close_ma ).astype(int)
# 添加条件指标图
fig.add_trace(go.Scatter(x=std_indicator.index, y=std_indicator, mode='lines', name='STD Condition', fill='tozeroy'), row=4, col=1)
# 更新图表的布局设置
fig.update_layout(height=600, width=800, title_text="蜡烛图与移动平均线")
fig.show()

最左侧的过滤效果并不佳,最左侧虽然满足过滤条件,但是图示上看,价格波动其实很小。

04,自适应的std,stdma(波动率的top30%过滤),#

在基础std,stdma基础上,增加动态过滤功能,通过设置一个合适的gateway_ma

定义:std_close > std_close_ma 且 std_close_ma > gateway_ma 为有效(意思是通过过滤条件) 那么有效数据在 整个数据比例,称为”有效” 率。
如果不考虑,std_close_ma_wbuf > gateway_ma
显然 “有效”率 是一个固定的数字。比如40%。
而实际我们希望有效率降低到目标有效率,target_ratio,比如30%,意味着要降低10%的有效率。
此时就要通过提高gateway_ma,来让有效的不在有效。从而丢弃部分std_close_ma较小的时间区间,保留波动性相对较大的部分。

05,价格变动的一致性(动量)#

除了考虑波动性,还需要考虑价格的变动是否有一致的方向。单纯的波动性增加,但价格突上突下无法形成显著方向,依然不行,所以期望过滤掉价格无方向的时间区间。
可以考虑如下的思路

20diff: 比如,t->T-20,t-1->T-21,等小柱子,计算小柱子,均值方差等状态。

结论:效果尚可。

# 计算收盘价的标准差
diff_close_wbuf = ohlcv_wbuf['Close'].diff(periods=20)
# 计算标准差的移动平均
diff_close_ma_wbuf = diff_close_wbuf.rolling(window=20).mean()
diff_close=diff_close_wbuf[wobuf_mask]
diff_close_ma=diff_close_ma_wbuf[wobuf_mask]
# 创建一个子图布局:2行1列
fig = make_subplots(rows=4, cols=1, shared_xaxes=True, vertical_spacing=0.02)
# 第一行添加蜡烛图
ohlcv_fig = ohlcv[['Open', 'High', 'Low', 'Close', 'Volume']].vbt.ohlcv.plot()
fig.add_trace(ohlcv_fig.data[0], row=1, col=1) # 添加蜡烛图数据
fig.add_trace(ohlcv_fig.data[1], row=2, col=1) # 添加交易量柱状图
# 第二行添加两个移动平均线
fig.add_trace(go.Scatter(x=ohlcv.index, y=diff_close, mode='lines', name='SMA 20'), row=3, col=1)
fig.add_trace(go.Scatter(x=ohlcv.index, y=diff_close_ma, mode='lines', name='SMA 50'), row=3, col=1)
# 创建条件指标
diff_indicator = ((diff_close > diff_close_ma )&(diff_close_ma>200*0.05)).astype(int) #20日达到5% 认为趋势性才足够大
# 添加条件指标图
fig.add_trace(go.Scatter(x=diff_indicator.index, y=diff_indicator, mode='lines', name='STD Condition', fill='tozeroy'), row=4, col=1)
# 更新图表的布局设置
fig.update_layout(height=600, width=800, title_text="蜡烛图与移动平均线")
fig.show()

06,价格变动的一致性,优化,过去值平滑处理,T-20用ma(T,20/4=5)代替#

缺点t->T-20,取值也取决于T-20,所以t->T-20,的过去价格T-20,用ma后的价格替代,等于做了平滑。

结论:噪点变少,

另一种变体,重新定义均线为 T-ma(T)[T-20]

07,结合上面2指标,对比同列#

std波动性,diff20趋势性

import plotly.graph_objects as go
from plotly.subplots import make_subplots
# 计算收盘价的标准差
std_close_wbuf = ohlcv_wbuf['Close'].rolling(window=20).std()
# 计算标准差的移动平均
std_close_ma_wbuf = std_close_wbuf.rolling(window=20).mean()
std_close=std_close_wbuf[wobuf_mask]
std_close_ma=std_close_ma_wbuf[wobuf_mask]
# 计算收盘价diff
diff_close_wbuf = ohlcv_wbuf['Close'] - ohlcv_wbuf['Close'].rolling(window=int(20/5)).mean().shift(20)
# 计算收盘价diff的移动平均
diff_close_ma_wbuf = diff_close_wbuf.rolling(window=20).mean()
diff_close=diff_close_wbuf[wobuf_mask]
diff_close_ma=diff_close_ma_wbuf[wobuf_mask]
# 创建一个子图布局:2行1列
fig = make_subplots(rows=4, cols=1, shared_xaxes=True, vertical_spacing=0.02)
# 第一行添加蜡烛图
ohlcv_fig = ohlcv[['Open', 'High', 'Low', 'Close', 'Volume']].vbt.ohlcv.plot()
fig.add_trace(ohlcv_fig.data[0], row=1, col=1) # 添加蜡烛图数据
fig.add_trace(ohlcv_fig.data[1], row=2, col=1) # 添加交易量柱状图
# 第二行添加两个移动平均线
fig.add_trace(go.Scatter(x=ohlcv.index, y=std_close, mode='lines', name='SMA 20'), row=3, col=1)
fig.add_trace(go.Scatter(x=ohlcv.index, y=std_close_ma, mode='lines', name='SMA 50'), row=3, col=1)
fig.add_trace(go.Scatter(x=ohlcv.index, y=diff_close, mode='lines', name='diff 20'), row=4, col=1)
fig.add_trace(go.Scatter(x=ohlcv.index, y=diff_close_ma, mode='lines', name='diff 50'), row=4, col=1)
# # 创建条件指标
# std_indicator = (std_close > std_close_ma ).astype(int)
# # 添加条件指标图
# fig.add_trace(go.Scatter(x=std_indicator.index, y=std_indicator, mode='lines', name='STD Condition', fill='tozeroy'), row=4, col=1)
# 更新图表的布局设置
fig.update_layout(height=600, width=800, title_text="蜡烛图与移动平均线")
fig.show()

vectorbt学习_50DMA之十过滤器
/posts/quant/b6a8a010/
作者
思想的巨人
发布于
2024-07-25
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时