交易信号有效性测算1——N日涨跌幅

在交易信号发出后,我们需要一些程序化的流程,来验证信号的有效性,其中信号发出后N日的涨跌幅就是一个比较常见的任务

布林带交易策略

我们以布林带(BOLL)交易策略为示例:

  • 中轨线 = N日移动平均线
  • 上轨线 = 中轨线 + k 标准差
  • 下轨线 = 中轨线 - k 标准差

交易信号:

  • 买点:收盘价下穿布林带下方
  • 卖点:收盘价上穿布林带上方

我们在python中,使用talib.BBANDS()来计算,参数包含:

  • 中轨线 = {timeperiod} 日移动平均线,移动平均线计算规则为 {matype}
  • 上轨线 = 中轨线 + {nbdevup} 标准差
  • 下轨线 = 中轨线 - {nbdevdn} 标准差

其中 matype值对应的算法为:0=SMA, 1=EMA, 2=WMA, 3=DEMA, 4=TEMA, 5=TRIMA, 6=KAMA, 7=MAMA, 8=T3

在这里插入图片描述

N日涨跌幅测算

统计信号发出后,计算N日的涨跌幅:

  1. 首先有个对比,即全时间段的N日涨跌幅
  2. 计算信号发出后N日的涨跌幅
  3. 由于有些信号存在连续性,因此统计跳过一些连续的交易日信号后,重新统计N日涨跌幅
def n_day_rise_fall(stock_df, n=10, skip_n=None):
    """计算未来N日的涨跌幅
    :param stock_df: 统计涨跌幅的dataframe
    :param n: 未来N日的涨跌幅
    :param skip_n: 跳过一段时间,统计未来N日的涨跌幅
    """
    stock_df.reset_index(inplace=True, drop=True)  # 重置index
    stock_df.sort_values("date", inplace=True)  # 按时间,从小到大排序
    collect_dict = {}
    
    # =========== 以每一天为参考,统计未来N日涨跌幅 ==============
    pct_series = stock_df['close'].pct_change(n)
    collect_dict['全部涨跌幅'] = (pct_series.dropna().values * 100).tolist()
    
    # =========== 统计买点之后未来N日涨跌幅 ==============
    buy_index = stock_df[stock_df['BUY'] == True].index
    n_after_buy_list = []
    for _buy_i in buy_index:
        close_values = stock_df.loc[_buy_i:(_buy_i + n), :]['close'].values
        range_value = (close_values[-1] - close_values[0]) / close_values[0]
        n_after_buy_list.append(range_value * 100)
    collect_dict[f"未来{n}日涨跌幅"] = n_after_buy_list
    
    # ======== 跳过买点的连续性,统计未来N日的涨跌幅 ==========
    if skip_n:
        skip_n_after_buy_list = []
        record_buy_index = -skip_n
        for _buy_i in buy_index:
            if _buy_i < record_buy_index + skip_n:
                continue
            close_values = stock_df.loc[_buy_i:(_buy_i + n), :]['close'].values
            range_value = (close_values[-1] - close_values[0]) / close_values[0]
            skip_n_after_buy_list.append(range_value * 100)
            record_buy_index = deepcopy(_buy_i)
        collect_dict[f'跳过{skip_n}的未来{n}日涨跌幅'] = skip_n_after_buy_list
    return collect_dict

示例

其中from data_utils import total_stock_market_data,这个是博主自己用的数据源,大家可以换成自己的

import pandas as pd
from data_utils import total_stock_market_data
from copy import deepcopy
import talib
import numpy as np


def n_day_rise_fall(stock_df, n=10, skip_n=None):
    """计算未来N日的涨跌幅
    :param stock_df: 统计涨跌幅的dataframe
    :param n: 未来N日的涨跌幅
    :param skip_n: 跳过一段时间,统计未来N日的涨跌幅
    """
    stock_df.reset_index(inplace=True, drop=True)  # 重置index
    stock_df.sort_values("date", inplace=True)  # 按时间,从小到大排序
    collect_dict = {}
    # =========== 以每一天为参考,统计未来N日涨跌幅 ==============
    pct_series = stock_df['close'].pct_change(n)
    collect_dict['全部涨跌幅'] = (pct_series.dropna().values * 100).tolist()
    # =========== 统计买点之后未来N日涨跌幅 ==============
    buy_index = stock_df[stock_df['BUY'] == True].index
    n_after_buy_list = []
    for _buy_i in buy_index:
        close_values = stock_df.loc[_buy_i:(_buy_i + n), :]['close'].values
        range_value = (close_values[-1] - close_values[0]) / close_values[0]
        n_after_buy_list.append(range_value * 100)
    collect_dict[f"未来{n}日涨跌幅"] = n_after_buy_list
    # ======== 跳过买点的连续性,统计未来N日的涨跌幅 ==========
    if skip_n:
        skip_n_after_buy_list = []
        record_buy_index = -skip_n
        for _buy_i in buy_index:
            if _buy_i < record_buy_index + skip_n:
                continue
            close_values = stock_df.loc[_buy_i:(_buy_i + n), :]['close'].values
            range_value = (close_values[-1] - close_values[0]) / close_values[0]
            skip_n_after_buy_list.append(range_value * 100)
            record_buy_index = deepcopy(_buy_i)
        collect_dict[f'跳过{skip_n}的未来{n}日涨跌幅'] = skip_n_after_buy_list
    return collect_dict


def cal_describe(data_dict):
    """统计每一个个股的情况"""
    des_dict = {}
    for _key, _value in data_dict.items():
        _value = np.array(_value)
        des_dict[_key] = {
            "num": len(_value),
            "mean": _value.mean(),
            "std": _value.std(),
            "1/4分位": np.percentile(_value, 25),
            "中位数": np.percentile(_value, 50),
            "3/4分位": np.percentile(_value, 75),
        }
    return des_dict


def add_boll_feature(df: pd.DataFrame):
    """计算指标[BUY][SELL]"""
    upper, middle, lower = talib.BBANDS(df["close"], timeperiod=14)  # 计算布林带指标
    df['boll_upper'] = upper
    df['boll_middle'] = middle
    df['boll_lower'] = lower
    # 判断买点与卖点
    df.dropna(inplace=True)
    df['BUY'] = None
    df['SELL'] = None
    for _index, series in df.iterrows():
        if series['close'] <= series['boll_lower']:
            df.loc[_index, "BUY"] = True
        if series['close'] >= series['boll_upper']:
            df.loc[_index, "SELL"] = True
    return df


def main():
    stock_dict = total_stock_market_data(limit=3, start_date="2020-01-01", end_date="2023-01-01")
    describe_collect_dict = {}
    for _key, _stock_df in stock_dict.items():
        _stock_df = _stock_df[["date", "open", "close", "high", 'low']]
        _stock_df.sort_values("date", inplace=True)
        stock_df = deepcopy(_stock_df)
        stock_df = add_boll_feature(stock_df)
        _coll_dict = n_day_rise_fall(stock_df, skip_n=5)
        describe_dict = cal_describe(_coll_dict)
        describe_collect_dict[_key] = describe_dict


if __name__ == '__main__':
    main()

比如数据源是:
在这里插入图片描述
最终得到的:

{
	'全部涨跌幅': {
		'num': 705, 
		'mean': 0.048260603236591246, 
		'std': 7.074501373770825, 
		'1/4分位': -4.712887188691961, 
		'中位数': -0.509262075967043, 
		'3/4分位': 4.109585014510864}, 
	'未来10日涨跌幅': {
		'num': 34, 
		'mean': 0.9538746236276364, 
		'std': 6.347669735599827, 
		'1/4分位': -3.5691535297657966, 
		'中位数': -0.6329642309802745, 
		'3/4分位': 5.306936708754319}, 
	'跳过5的未来10日涨跌幅': {
		'num': 19, 
		'mean': -0.7768875022887046, 
		'std': 5.618893194327587, 
		'1/4分位': -4.332845170390464, 
		'中位数': -1.5776713355815666, 
		'3/4分位': 1.9155965506750263}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呆萌的代Ma

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值