quantopian寻找策略之mean_reversion

股价有向均线回归的趋势,利用这个特点,可以在技术指标处于超卖阶段寻找那些上涨速度快的流通性好的股票买入,形成下面的策略。策略来源quantopian。
对于市场上流通性最好的1500只股票在pipeline中先进行一波过滤:
1.年收益率排名前500
2.20日平均成交量大于100万股
3.股价高于1刀
4.rsi小于50
把过滤出的股票按照200日收益降序排列取前十名放入待买股票列表。
接下来用标普500指数的200日均线的98%做风控,指数走弱全部清仓并且不开新仓。
卖出持仓中不在待买股票列表中的标的。
买入持仓中没有且在待买股票列表中的标的,仓位按股票个数平均分配。

这个策略主要是用200日收益去向250日收益去靠拢。

几个需要注意的函数:

class roc_200days(CustomFactor):
    inputs = [USEquityPricing.close] 
    window_length = 200+1

    def compute(self, today, assets, out, close):
        print(len(close[-1]))
        out[:] = ((close[-1] - close[0]) / close[0]) * 100
        print(len(out))
        print(out)

运行时输出:

2010-01-04 21:45  PRINT 7932
2010-01-04 21:45  PRINT 7932
2010-01-04 21:45  PRINT [ 196.97048283  178.26086957  107.60141788 ...,           nan   13.84790011
  112.76595745]

这里面定义了一个custom_factor,close是一个201*7932的ndarray。上面这个类roc_200days的作用是不断获取200日收益。
在这里插入图片描述

import quantopian.algorithm as algo
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.filters import QTradableStocksUS, Q1500US
from quantopian.pipeline.factors import SimpleMovingAverage, RSI, CustomFactor, Returns, Latest
from quantopian.algorithm import attach_pipeline, pipeline_output

class roc_200days(CustomFactor):
    inputs = [USEquityPricing.close] 
    window_length = 200+1

    def compute(self, today, assets, out, close):
        out[:] = ((close[-1] - close[0]) / close[0]) * 100


def initialize(context):
    set_commission(commission.PerTrade(cost=0.00))
    set_slippage(slippage.FixedSlippage(spread=0.00))
    set_long_only()
 
    schedule_function(is_positive_trend, date_rules.week_start(), time_rules.market_open(hours=0, minutes=59), half_days=False)
    schedule_function(rebalance_sell, date_rules.week_start(), time_rules.market_open(hours=1), half_days=False)
    schedule_function(rebalance_buy, date_rules.week_start(), time_rules.market_open(hours=2), half_days=False)
    schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close(), half_days=False)

    algo.attach_pipeline(make_pipeline(), 'my_pipeline')

    
def make_pipeline():
    TOTAL_STOCKS = 500
    returns_1_yr = Returns(window_length = 252)
    base_universe = returns_1_yr.top(TOTAL_STOCKS, mask = Q1500US())
    
    avg_volume = SimpleMovingAverage(inputs=[USEquityPricing.volume],window_length=20)
    filter_volume = avg_volume > 1000000

    last_price = Latest(inputs=[USEquityPricing.close], window_length=1) 
    filter_price = last_price > 1

    rsi = RSI(inputs=[USEquityPricing.close], window_length=3)
    filter_overbought = rsi < 50

    roc = roc_200days()
    
    stocks_to_trade = base_universe & filter_volume & filter_price & filter_overbought

    return Pipeline(
        columns = {
            'stocks': stocks_to_trade,
            'avg_volume': avg_volume,
            'roc': roc,
        },
        screen = (stocks_to_trade)
    )


def before_trading_start(context, data):
    context.my_output = pipeline_output('my_pipeline')
    context.candidates = context.my_output.sort_values('roc', ascending=False).head(10).index.tolist()
    
    
def is_positive_trend(context, data):  
    can_trade = False
    spy = symbol('SPY')
    price_history = data.history(spy, fields='close', bar_count=200, frequency='1d')      
    context.spy_close = data.current(spy,'close')
    context.sma200 = price_history.mean()
    context.sma200_buffered = context.sma200 * 0.98
    if context.spy_close > context.sma200_buffered:
        can_trade = True 
    context.is_trend = can_trade

    
def rebalance_sell(context, data):  
    if not context.is_trend:
        empty_bags(context, data)
    else:   
        for security in context.portfolio.positions:
            if security not in context.candidates and data.can_trade(security):
                order_target_percent(security, 0)  

                
def rebalance_buy(context, data): 
    if get_open_orders():
        log.info("Unexpected open orders: " + str(len(context.portfolio.positions)))
        print_orders()

    if context.is_trend is False:
        return

    needed_cash = get_cash_amount(context, data)
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security): 
            if(needed_cash < context.portfolio.cash):
                order_value(security, needed_cash)

    
def my_record_vars(context, data):
    record(spy=context.spy_close, sma200=context.sma200, sma200_buffered=context.sma200_buffered)

        
def get_cash_amount(context, data):
    weight = 0
    num_stocks = 0
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security):
            if data.can_trade(security):
                num_stocks = num_stocks + 1  

    if num_stocks > 0:
        weight = 1.0 / num_stocks   
    spend = context.portfolio.cash * weight  
    return spend


def empty_bags(context, data):
    for security in context.portfolio.positions:
        if data.can_trade(security):
            order_target_percent(security, 0)

            
def print_orders():
    open_orders = get_open_orders()
    if len(open_orders) == 0:
        return
    for security, orders in open_orders.iteritems():
        for order in orders:
            log.info("Active order for " + str(order.amount) + " shares of " + str(security))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
import numpy as np import pandas as pd import talib def initialize(context): context.symbol = 'BTCUSDT' context.window_size = 5 context.deviation = 1 context.trade_size = 0.01 context.stop_loss = 0.05 context.take_profit = 0.1 schedule_function(rebalance, date_rules.every_day(), time_rules.market_open()) def rebalance(context, data): price = data.history(context.symbol, 'close', context.window_size + 1, '1d') signal = mean_reversion_signal(price, context.window_size, context.deviation) current_position = context.portfolio.positions[context.symbol].amount if signal[-1] == 1 and current_position <= 0: target_position_size = context.trade_size / data.current(context.symbol, 'close') order_target_percent(context.symbol, target_position_size) elif signal[-1] == -1 and current_position >= 0: order_target(context.symbol, 0) elif current_position > 0: current_price = data.current(context.symbol, 'close') stop_loss_price = current_price * (1 - context.stop_loss) take_profit_price = current_price * (1 + context.take_profit) if current_price <= stop_loss_price or current_price >= take_profit_price: order_target(context.symbol, 0) def moving_average(x, n): ma = talib.SMA(x, timeperiod=n) return ma def std_deviation(x, n): std = talib.STDDEV(x, timeperiod=n) return std def mean_reversion_signal(price, window_size, deviation): ma = moving_average(price, window_size) std = std_deviation(price, window_size) upper_band = ma + deviation * std lower_band = ma - deviation * std signal = np.zeros_like(price) signal[price > upper_band] = -1 # 卖出信号 signal[price < lower_band] = 1 # 买入信号 return signal ''' 运行回测 ''' start_date = pd.to_datetime('2019-01-01', utc=True) end_date = pd.to_datetime('2021-01-01', utc=True) results = run_algorithm( start=start_date, end=end_date, initialize=initialize, capital_base=10000, data_frequency='daily', bundle='binance' ) ''' 查看回测结果 ''' print(results.portfolio_value)格式错误
05-26

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值