Python量化交易学习——Part9:基于放量技术因子的策略实战

话不多说,直接进入正题
股票池:沪深300
买入策略:选择过去收盘价标准差小于0.05,且量比大于3的股票,当第二天高开的时候进行买入;
卖出策略:卖出条件为收益30%或者亏损7%;
首先我们可以先新建一个文件用于保存放量因子这个技术函数,我这里命名为volume_strategy.py,函数代码如下:

import numpy as np
import pandas as pd
from gm.api import *
import datetime
import statsmodels.api as sm
from dateutil.relativedelta import relativedelta
from sklearn.preprocessing import MinMaxScaler

"""
放量策略:
股票池:以XXX股票池为基础,过去收盘价标准差小于0.05的股票列入关注股票
买入策略:当第N日的成交量相比与第N-1日的成交量大于5的时候买入;
卖出策略:卖出条件为收益30%或者亏损7%;
"""
# 输入值:index:指数代码 now:现在时间 threshold:标准差大小
#返回值:股票清单
def volume_strategy_stock_pool (index,now,threshold):
    # 建立股票池
    last_day = get_previous_trading_date("SHSE",now) # 获取前一交易日的时间
    symbol_array = stk_get_index_constituents(index).sort_values(["symbol"],ascending=False)   #获取成分股,按照股票代码从大到小排序
    symbol_list = symbol_array["symbol"].values # 提取股票代码
    symbol_list_final = []

    for symbol in symbol_list:
        data = history_n(symbol=symbol, frequency="1d", count=14, end_time=last_day, fields="close", adjust=ADJUST_PREV, df=True)
        if data.empty == True: #判断数据是否为空
            pass
            #print("数据无效",symbol)
        else:
            close = data["close"].values
            close_std = np.std(close)
            if close_std < threshold:
                symbol_list_final.append(symbol)

    return symbol_list_final  #返回股票清单

# 输入值 index:股票清单 now:目前时间 symbol_count:总持仓股票数
# 返回值 symbol_buy_price_list,买入股票清单,dataframe类型 (股票,价格)
def volume_strategy_buy (index,now,symbol_count):
    # 买入股票
    last_day = get_previous_trading_date("SHSE", now)  # 获取前一交易日的时间
    symbol_buy_price = {}
    symbol_buy_price_list = []
    for symbol in index:
        data = history_n(symbol=symbol, frequency="1d", count=2, end_time=last_day, fields="volume", adjust=ADJUST_PREV, df=True)
        if data.empty == True or len(data["volume"].values) != 2: #判断数据是否为空
            pass  # print("数据无效",symbol)
        else:
            volume = data["volume"].values
            if volume[1]/volume[0] >= 3:
                current_price = current(symbol)[0]["price"]
                last_price = history_n(symbol=symbol, frequency="1d", count=1, end_time=last_day, fields="close", adjust=ADJUST_PREV, df=True)["close"].values
                if np.log(current_price/last_price) > 0: # 目前价格高于昨日收盘价,高开
                    order_target_percent(symbol=symbol,percent=1/symbol_count,order_type=OrderType_Market,position_side=PositionSide_Long)
                    symbol_buy_price[symbol] = current_price
                    print("buy",symbol,current_price)

    symbol_buy_price_list = pd.DataFrame((list(symbol_buy_price.items())), columns=["symbol", "price"])
    return symbol_buy_price_list

# 输入值 symbol_buy_price,买入股票清单,dataframe类型 (股票,价格)
# 返回值 sell_symbol_list,卖出股票清单,list类型
def volume_strategy_sell(symbol_buy_price):
    #卖出股票
    sell_symbol_list = []
    buy_price_list = list(symbol_buy_price["price"].values)
    symbol_list = list(symbol_buy_price["symbol"].values)
    for num in range(0,len(symbol_list)-1):
        current_price = current(symbol_list[num])[0]["price"]
        buy_price = buy_price_list[num]
        if current_price > buy_price*1.3 or current_price < buy_price*0.93 :
            order_target_percent(symbol=symbol_list[num],percent=0,order_type=OrderType_Market,position_side=PositionSide_Long)
            print("sell",symbol_list[num],"卖出价:",current_price,"买入价:",buy_price,"收益:",(current_price-buy_price)/current_price)
            sell_symbol_list.append(symbol_list[num])
    return sell_symbol_list

该文件中一共包含3个函数:
第一个函数是volume_strategy_stock_pool (index,now,threshold),这个函数的作用从现有股票池中选择收盘价连续14天标准差小于threshold的股票,形成一个备选股清单。因为有些股票有过停牌,所以我们剔除了那些无效数据。否则做标准差的时候会报错。
第二个函数是volume_strategy_buy (index,now,symbol_count),是购买股票的函数,我们根据备选股清单进行逐个排查,选择量比大于3的股票,如果第二天开盘价格大于前一天的收盘价,则买入;
第三个函数是volume_strategy_sell(symbol_buy_price),是卖出股票的函数,如果盈利超过30%,或者亏损超过7%,则卖出,否则仍然持有。
之后我们通过主函数调用,新建py文件volume_strategy_test.py,代码如下:

# coding=utf-8
from __future__ import print_function, absolute_import

import pandas as pd
from gm.api import *
import volume_strategy as vs

def init(context):
    # 每天14:50 定时执行algo任务,
    # algo执行定时任务函数,只能传context参数
    # date_rule执行频率,目前暂时支持1d、1w、1m,其中1w、1m仅用于回测,实时模式1d以上的频率,需要在algo判断日期
    # time_rule执行时间, 注意多个定时任务设置同一个时间点,前面的定时任务会被后面的覆盖
    context.symbol = "SHSE.000922"  # 沪深300
    context.num = 5 # 持仓做多股票种类
    context.threshold = 0.05  #选股标准差
    context.symbol_list = pd.DataFrame() #买入股票清单(股票,买入价格)
    schedule(schedule_func=algo, date_rule='1d', time_rule='09:31:00')

def algo(context):
    # 以沪深300指数为基础,选择14天标准差小于0.05的股票建立股票池
    symbol_list_final = vs.volume_strategy_stock_pool(context.symbol,context.now,context.threshold)
    # 判断买入股票的数量是否大于能持仓的最大数量
    if len(context.symbol_list.index) <= context.num:
        symbol_price_list = vs.volume_strategy_buy(symbol_list_final,context.now,context.num)  # 从股票池中获取量比大于3的股票作为标的股票,进行买入
        if len(symbol_price_list) != 0: # 如果选择出新的标的股票,则把标的股票加入到买入股票清单中
            context.symbol_list = pd.concat([context.symbol_list,symbol_price_list],axis=0).drop_duplicates(subset=['symbol'],keep='first') # 删除symbol重复项,只保留第一项
            context.symbol_list = context.symbol_list.reset_index(drop=True) # 重置行索引,不保留原索引作为列
    if len(context.symbol_list.index) != 0:
        sell_symbol_list = vs.volume_strategy_sell(context.symbol_list) #卖出股票,获得卖出股票清单
        if len(sell_symbol_list) != 0:
            for symbol in sell_symbol_list:  # 从股票清单中删除已经卖出的股票
                rows_to_delete = context.symbol_list[context.symbol_list['symbol'] == symbol].index
                context.symbol_list = context.symbol_list.drop(rows_to_delete)
                print(context.symbol_list)



# 查看最终的回测结果
def on_backtest_finished(context, indicator):
    print(indicator)


if __name__ == '__main__':
    '''
        strategy_id策略ID, 由系统生成
        filename文件名, 请与本文件名保持一致
        mode运行模式, 实时模式:MODE_LIVE回测模式:MODE_BACKTEST
        token绑定计算机的ID, 可在系统设置-密钥管理中生成
        backtest_start_time回测开始时间
        backtest_end_time回测结束时间
        backtest_adjust股票复权方式, 不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
        backtest_initial_cash回测初始资金
        backtest_commission_ratio回测佣金比例
        backtest_slippage_ratio回测滑点比例
        backtest_match_mode市价撮合模式,以下一tick/bar开盘价撮合:0,以当前tick/bar收盘价撮合:1
    '''
    run(strategy_id='自己的策略',
        filename='volume_strategy_test.py',
        mode=MODE_BACKTEST,
        token='自己的token码',
        backtest_start_time='2020-01-01 09:30:00',
        backtest_end_time='2024-6-20 15:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001,
        backtest_match_mode=1)

在主函数def algo(context)中,我们先调用了volume_strategy_stock_pool()函数,得到了备选股票的清单,之后我们通过volume_strategy_buy()函数对股票进行买入操作,但因为我们的资金是有效的,所以我们只能持仓一定数量的股票,在这里我假设是5只,所以当持仓数量超过5只的时候,我们便不用再买入股票了,只需要看是否需要卖出。当有新的股票进行买卖资源池中,我们需要进行增删操作。要不每次都需要判断已经卖出的股票是否还需要卖出,浪费时间。
回测结果如下:
在这里插入图片描述
从回测结果看,该策略的收益还是可以的,4年半收益为97.81%,但在个股的操作上,看起来并不是十分明智,以交通银行为例,买入和卖出的时机都不算好,我们可以适当调节买入策略或者卖出策略,比如量比大于5买入,或者收益大于40%卖出,或者其他卖出方式,看是否可以得到更好的结果。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值