经典的股票/期货量化交易策略,拿来即用的Python策略源码

声明:本文策略源码均来自掘金量化示例策略库,仅供参考!

一、股票策略

1.多因子选股

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
import numpy as np
from gm.api import *
from pandas import DataFrame
'''
本策略每隔1个月定时触发,根据Fama-French三因子模型对每只股票进行回归,得到其alpha值。
假设Fama-French三因子模型可以完全解释市场,则alpha为负表明市场低估该股,因此应该买入。
策略思路:
计算市场收益率、个股的账面市值比和市值,并对后两个进行了分类,
根据分类得到的组合分别计算其市值加权收益率、SMB和HML. 
对各个股票进行回归(假设无风险收益率等于0)得到alpha值.
选取alpha值小于0并为最小的10只股票进入标的池
平掉不在标的池的股票并等权买入在标的池的股票
回测数据:SHSE.000300的成份股
回测时间:2017-07-01 08:00:00到2017-10-01 16:00:00
'''
def init(context):
    # 每月第一个交易日的09:40 定时执行algo任务
    schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')
    print(order_target_percent(symbol='SHSE.600000', percent=0.5, order_type=OrderType_Market,
                         position_side=PositionSide_Long))
    # 数据滑窗
    context.date = 20
    # 设置开仓的最大资金量
    context.ratio = 0.8
    # 账面市值比的大/中/小分类
    context.BM_BIG = 3.0
    context.BM_MID = 2.0
    context.BM_SMA = 1.0
    # 市值大/小分类
    context.MV_BIG = 2.0
    context.MV_SMA = 1.0
# 计算市值加权的收益率,MV为市值的分类,BM为账目市值比的分类
def market_value_weighted(stocks, MV, BM):
    select = stocks[(stocks.NEGOTIABLEMV == MV) & (stocks.BM == BM)]
    market_value = select['mv'].values
    mv_total = np.sum(market_value)
    mv_weighted = [mv / mv_total for mv in market_value]
    stock_return = select['return'].values
    # 返回市值加权的收益率的和
    return_total = []
    for i in range(len(mv_weighted)):
        return_total.append(mv_weighted[i] * stock_return[i])
    return_total = np.sum(return_total)
    return return_total
def algo(context):
    # 获取上一个交易日的日期
    last_day = get_previous_trading_date(exchange='SHSE', date=context.now)
    # 获取沪深300成份股
    context.stock300 = get_history_constituents(index='SHSE.000300', start_date=last_day,
                                                end_date=last_day)[0]['constituents'].keys()
    # 获取当天有交易的股票
    not_suspended = get_history_instruments(symbols=context.stock300, start_date=last_day, end_date=last_day)
    not_suspended = [item['symbol'] for item in not_suspended if not item['is_suspended']]
    fin = get_fundamentals(table='tq_sk_finindic', symbols=not_suspended, start_date=last_day, end_date=last_day,
                           fields='PB,NEGOTIABLEMV', df=True)
    # 计算账面市值比,为P/B的倒数
    fin['PB'] = (fin['PB'] ** -1)
    # 计算市值的50%的分位点,用于后面的分类
    size_gate = fin['NEGOTIABLEMV'].quantile(0.50)
    # 计算账面市值比的30%和70%分位点,用于后面的分类
    bm_gate = [fin['PB'].quantile(0.30), fin['PB'].quantile(0.70)]
    fin.index = fin.symbol
    x_return = []
    # 对未停牌的股票进行处理
    for symbol in not_suspended:
        # 计算收益率
        close = history_n(symbol=symbol, frequency='1d', count=context.date + 1, end_time=last_day, fields='close',
                          skip_suspended=True, fill_missing='Last', adjust=ADJUST_PREV, df=True)['close'].values
        stock_return = close[-1] / close[0] - 1
        pb = fin['PB'][symbol]
        market_value = fin['NEGOTIABLEMV'][symbol]
        # 获取[股票代码. 股票收益率, 账面市值比的分类, 市值的分类, 流通市值]
        if pb < bm_gate[0]:
            if market_value < size_gate:
                label = [symbol, stock_return, context.BM_SMA, context.MV_SMA, market_value]
            else:
                label = [symbol, stock_return, context.BM_SMA, context.MV_BIG, market_value]
        elif pb < bm_gate[1]:
            if market_value < size_gate:
                label = [symbol, stock_return, context.BM_MID, context.MV_SMA, market_value]
            else:
                label = [symbol, stock_return, context.BM_MID, context.MV_BIG, market_value]
        elif market_value < size_gate:
            label = [symbol, stock_return, context.BM_BIG, context.MV_SMA, market_value]
        else:
            label = [symbol, stock_return, context.BM_BIG, context.MV_BIG, market_value]
        if len(x_return) == 0:
            x_return = label
        else:
            x_return = np.vstack([x_return, label])
    stocks = DataFrame(data=x_return, columns=['symbol', 'return', 'BM', 'NEGOTIABLEMV', 'mv'])
    stocks.index = stocks.symbol
    columns = ['return', 'BM', 'NEGOTIABLEMV', 'mv']
    for column in columns:
        stocks[column] = stocks[column].astype(np.float64)
    # 计算SMB.HML和市场收益率
    # 获取小市值组合的市值加权组合收益率
    smb_s = (market_value_weighted(stocks, context.MV_SMA, context.BM_SMA) +
             market_value_weighted(stocks, context.MV_SMA, context.BM_MID) +
             market_value_weighted(stocks, context.MV_SMA, context.BM_BIG)) / 3
    # 获取大市值组合的市值加权组合收益率
    smb_b = (market_value_weighted(stocks, context.MV_BIG, context.BM_SMA) +
             market_value_weighted(stocks, context.MV_BIG, context.BM_MID) +
             market_value_weighted(stocks, context.MV_BIG, context.BM_BIG)) / 3
    smb = smb_s - smb_b
    # 获取大账面市值比组合的市值加权组合收益率
    hml_b = (market_value_weighted(stocks, context.MV_SMA, 3) +
             market_value_weighted(stocks, context.MV_BIG, context.BM_BIG)) / 2
    # 获取小账面市值比组合的市值加权组合收益率
    hml_s = (market_value_weighted(stocks, context.MV_SMA, context.BM_SMA) +
             market_value_weighted(stocks, context.MV_BIG, context.BM_SMA)) / 2
    hml = hml_b - hml_s
    close = history_n(symbol='SHSE.000300', frequency='1d', count=context.date + 1,
                      end_time=last_day, fields='close', skip_suspended=True,
                      fill_missing='Last', adjust=ADJUST_PREV, df=True)['close'].values
    market_return = close[-1] / close[0] - 1
    coff_pool = []
    # 对每只股票进行回归获取其alpha值
    for stock in stocks.index:
        x_value = np.array([[market_return], [smb], [hml], [1.0]])
        y_value = np.array([stocks['return'][stock]])
        # OLS估计系数
        coff = np.linalg.lstsq(x_value.T, y_value)[0][3]
        coff_pool.append(coff)
    # 获取alpha最小并且小于0的10只的股票进行操作(若少于10只则全部买入)
    stocks['alpha'] = coff_pool
    stocks = stocks[stocks.alpha < 0].sort_values(by='alpha').head(10)
    symbols_pool = stocks.index.tolist()
    positions = context.account().positions()
    # 平不在标的池的股票
    for position in positions:
        symbol = position['symbol']
        if symbol not in symbols_pool:
            order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print('市价单平不在标的池的', symbol)
    # 获取股票的权重
    percent = context.ratio / len(symbols_pool)
    # 买在标的池中的股票
    for symbol in symbols_pool:
        order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
                             position_side=PositionSide_Long)
        print(symbol, '以市价单调多仓到仓位', percent)
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-07-01 08:00:00',
        backtest_end_time='2017-10-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

2.日内回转交易

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
try:
    import talib
except:
    print('请安装TA-Lib库')
from gm.api import *
'''
本策略首先买入SHSE.600000股票10000股
随后根据60s的数据来计算MACD(12,26,9)线,并在MACD>0的时候买入100股,MACD<0的时候卖出100股
但每日操作的股票数不超过原有仓位,并于收盘前把仓位调整至开盘前的仓位
回测数据为:SHSE.600000的60s数据
回测时间为:2017-09-01 08:00:00到2017-10-01 16:00:00
'''
def init(context):
    # 设置标的股票
    context.symbol = 'SHSE.600000'
    # 用于判定第一个仓位是否成功开仓
    context.first = 0
    # 订阅浦发银行, bar频率为1min
    subscribe(symbols=context.symbol, frequency='60s', count=35)
    # 日内回转每次交易100股
    context.trade_n = 100
    # 获取昨今天的时间
    context.day = [0, 0]
    # 用于判断是否触发了回转逻辑的计时
    context.ending = 0
def on_bar(context, bars):
    bar = bars[0]
    if context.first == 0:
        # 最开始配置仓位
        # 需要保持的总仓位
        context.total = 10000
        # 购买10000股浦发银行股票
        order_volume(symbol=context.symbol, volume=context.total, side=PositionSide_Long,
                     order_type=OrderType_Market, position_effect=PositionEffect_Open)
        print(context.symbol, '以市价单开多仓10000股')
        context.first = 1.
        day = bar.bob.strftime('%Y-%m-%d')
        context.day[-1] = day[-2:]
        # 每天的仓位操作
        context.turnaround = [0, 0]
        return
    # 更新最新的日期
    day = bar.bob.strftime('%Y-%m-%d %H:%M:%S')
    context.day[0] = bar.bob.day
    # 若为新的一天,获取可用于回转的昨仓
    if context.day[0] != context.day[-1]:
        context.ending = 0
        context.turnaround = [0, 0]
    if context.ending == 1:
        return
    # 若有可用的昨仓则操作
    if context.total >= 0:
        # 获取时间序列数据
        symbol = bar['symbol']
        recent_data = context.data(symbol=symbol, frequency='60s', count=35, fields='close')
        # 计算MACD线
        macd = talib.MACD(recent_data['close'].values)[0][-1]
        # 根据MACD>0则开仓,小于0则平仓
        if macd > 0:
            # 多空单向操作都不能超过昨仓位,否则最后无法调回原仓位
            if context.turnaround[0] + context.trade_n < context.total:
                # 计算累计仓位
                context.turnaround[0] += context.trade_n
                order_volume(symbol=context.symbol, volume=context.trade_n, side=PositionSide_Long,
                             order_type=OrderType_Market, position_effect=PositionEffect_Open)
                print(symbol, '市价单开多仓', context.trade_n, '股')
        elif macd < 0:
            if context.turnaround[1] + context.trade_n < context.total:
                context.turnaround[1] += context.trade_n
                order_volume(symbol=context.symbol, volume=context.trade_n, side=PositionSide_Short,
                             order_type=OrderType_Market, position_effect=PositionEffect_Close)
                print(symbol, '市价单平多仓', context.trade_n, '股')
        # 临近收盘时若仓位数不等于昨仓则回转所有仓位
        if day[11:16] == '14:55' or day[11:16] == '14:57':
            position = context.account().position(symbol=context.symbol, side=PositionSide_Long)
            if position['volume'] != context.total:
                order_target_volume(symbol=context.symbol, volume=context.total, order_type=OrderType_Market,
                                    position_side=PositionSide_Long)
                print('市价单回转仓位操作...')
                context.ending = 1
        # 更新过去的日期数据
        context.day[-1] = context.day[0]
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-09-01 08:00:00',
        backtest_end_time='2017-10-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=2000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

3.指数增强

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
import numpy as np
from gm.api import *
from pandas import DataFrame
'''
本策略以0.8为初始权重跟踪指数标的沪深300中权重大于0.35%的成份股.
个股所占的百分比为(0.8*成份股权重)*100%.然后根据个股是否:
1.连续上涨5天 2.连续下跌5天
来判定个股是否为强势股/弱势股,并对其把权重由0.8调至1.0或0.6
回测时间为:2017-07-01 08:50:00到2017-10-01 17:00:00
'''
def init(context):
    # 资产配置的初始权重,配比为0.6-0.8-1.0
    context.ratio = 0.8
    # 获取沪深300当时的成份股和相关数据
    stock300 = get_history_constituents(index='SHSE.000300', start_date='2017-06-30', end_date='2017-06-30')[0][
        'constituents']
    stock300_symbol = []
    stock300_weight = []
    for key in stock300:
        # 保留权重大于0.35%的成份股
        if (stock300[key] / 100) > 0.0035:
            stock300_symbol.append(key)
            stock300_weight.append(stock300[key] / 100)
    context.stock300 = DataFrame([stock300_weight], columns=stock300_symbol, index=['weight']).T
    print('选择的成分股权重总和为: ', np.sum(stock300_weight))
    subscribe(symbols=stock300_symbol, frequency='1d', count=5, wait_group=True)
def on_bar(context, bars):
    # 若没有仓位则按照初始权重开仓
    for bar in bars:
        symbol = bar['symbol']
        position = context.account().position(symbol=symbol, side=PositionSide_Long)
        if not position:
            buy_percent = context.stock300['weight'][symbol] * context.ratio
            order_target_percent(symbol=symbol, percent=buy_percent, order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print(symbol, '以市价单开多仓至仓位:', buy_percent)
        else:
            # 获取过去5天的价格数据,若连续上涨则为强势股,权重+0.2;若连续下跌则为弱势股,权重-0.2
            recent_data = context.data(symbol=symbol, frequency='1d', count=5, fields='close')['close'].tolist()
            if all(np.diff(recent_data) > 0):
                buy_percent = context.stock300['weight'][symbol] * (context.ratio + 0.2)
                order_target_percent(symbol=symbol, percent=buy_percent, order_type=OrderType_Market,
                                     position_side=PositionSide_Long)
                print('强势股', symbol, '以市价单调多仓至仓位:', buy_percent)
            elif all(np.diff(recent_data) < 0):
                buy_percent = context.stock300['weight'][symbol] * (context.ratio - 0.2)
                order_target_percent(symbol=symbol, percent=buy_percent, order_type=OrderType_Market,
                                     position_side=PositionSide_Long)
                print('弱势股', symbol, '以市价单调多仓至仓位:', buy_percent)
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-07-01 08:50:00',
        backtest_end_time='2017-10-01 17:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

4.行业轮动

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
import numpy as np
from gm.api import *
'''
本策略每隔1个月定时触发计算SHSE.000910.SHSE.000909.SHSE.000911.SHSE.000912.SHSE.000913.SHSE.000914
(300工业.300材料.300可选.300消费.300医药.300金融)这几个行业指数过去
20个交易日的收益率并选取了收益率最高的指数的成份股获取并获取了他们的市值数据
随后把仓位调整至市值最大的5只股票上
回测数据为:SHSE.000910.SHSE.000909.SHSE.000911.SHSE.000912.SHSE.000913.SHSE.000914和他们的成份股
回测时间为:2017-07-01 08:00:00到2017-10-01 16:00:00
'''
def init(context):
    # 每月第一个交易日的09:40 定时执行algo任务
    schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')
    # 用于筛选的行业指数
    context.index = ['SHSE.000910', 'SHSE.000909', 'SHSE.000911', 'SHSE.000912', 'SHSE.000913', 'SHSE.000914']
    # 用于统计数据的天数
    context.date = 20
    # 最大下单资金比例
    context.ratio = 0.8
def algo(context):
    # 获取当天的日期
    today = context.now
    # 获取上一个交易日
    last_day = get_previous_trading_date(exchange='SHSE', date=today)
    return_index = []
    # 获取并计算行业指数收益率
    for i in context.index:
        return_index_his = history_n(symbol=i, frequency='1d', count=context.date, fields='close,bob',
                                     fill_missing='Last', adjust=ADJUST_PREV, end_time=last_day, df=True)
        return_index_his = return_index_his['close'].values
        return_index.append(return_index_his[-1] / return_index_his[0] - 1)
    # 获取指定数内收益率表现最好的行业
    sector = context.index[np.argmax(return_index)]
    print('最佳行业指数是: ', sector)
    # 获取最佳行业指数成份股
    symbols = get_history_constituents(index=sector, start_date=last_day, end_date=last_day)[0]['constituents'].keys()
    # 获取当天有交易的股票
    not_suspended_info = get_history_instruments(symbols=symbols, start_date=today, end_date=today)
    not_suspended_symbols = [item['symbol'] for item in not_suspended_info if not item['is_suspended']]
    # 获取最佳行业指数成份股的市值,从大到小排序并选取市值最大的5只股票
    fin = get_fundamentals(table='tq_sk_finindic', symbols=not_suspended_symbols, start_date=last_day,
                           end_date=last_day, limit=5, fields='NEGOTIABLEMV', order_by='-NEGOTIABLEMV', df=True)
    fin.index = fin['symbol']
    # 计算权重
    percent = 1.0 / len(fin.index) * context.ratio
    # 获取当前所有仓位
    positions = context.account().positions()
    # 如标的池有仓位,平不在标的池的仓位
    for position in positions:
        symbol = position['symbol']
        if symbol not in fin.index:
            order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print('市价单平不在标的池的', symbol)
    # 对标的池进行操作
    for symbol in fin.index:
        order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
                             position_side=PositionSide_Long)
        print(symbol, '以市价单调整至仓位', percent)
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-07-01 08:00:00',
        backtest_end_time='2017-10-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

5.集合竞价选股

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
from gm.api import *
'''
本策略通过获取SHSE.000300沪深300的成份股数据并统计其30天内
开盘价大于前收盘价的天数,并在该天数大于阈值10的时候加入股票池
随后对不在股票池的股票平仓并等权配置股票池的标的,每次交易间隔1个月.
回测数据为:SHSE.000300在2015-01-15的成份股
回测时间为:2017-07-01 08:00:00到2017-10-01 16:00:00
'''
def init(context):
    # 每月第一个交易日的09:40 定时执行algo任务
    schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')
    # context.count_bench累计天数阙值
    context.count_bench = 10
    # 用于对比的天数
    context.count = 30
    # 最大交易资金比例
    context.ratio = 0.8
def algo(context):
    # 获取当前时间
    now = context.now
    # 获取上一个交易日
    last_day = get_previous_trading_date(exchange='SHSE', date=now)
    # 获取沪深300成份股
    context.stock300 = get_history_constituents(index='SHSE.000300', start_date=last_day,
                                                end_date=last_day)[0]['constituents'].keys()
    # 获取当天有交易的股票
    not_suspended_info = get_history_instruments(symbols=context.stock300, start_date=now, end_date=now)
    not_suspended_symbols = [item['symbol'] for item in not_suspended_info if not item['is_suspended']]
    trade_symbols = []
    if not not_suspended_symbols:
        print('没有当日交易的待选股票')
        return
    for stock in not_suspended_symbols:
        recent_data = history_n(symbol=stock, frequency='1d', count=context.count, fields='pre_close,open',
                                fill_missing='Last', adjust=ADJUST_PREV, end_time=now, df=True)
        diff = recent_data['open'] - recent_data['pre_close']
        # 获取累计天数超过阙值的标的池.并剔除当天没有交易的股票
        if len(diff[diff > 0]) >= context.count_bench:
            trade_symbols.append(stock)
    print('本次股票池有股票数目: ', len(trade_symbols))
    # 计算权重
    percent = 1.0 / len(trade_symbols) * context.ratio
    # 获取当前所有仓位
    positions = context.account().positions()
    # 如标的池有仓位,平不在标的池的仓位
    for position in positions:
        symbol = position['symbol']
        if symbol not in trade_symbols:
            order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print('市价单平不在标的池的', symbol)
    # 对标的池进行操作
    for symbol in trade_symbols:
        order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
                             position_side=PositionSide_Long)
        print(symbol, '以市价单调整至权重', percent)
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-07-01 08:00:00',
        backtest_end_time='2017-10-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

6.机器学习

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
from datetime import datetime
import numpy as np
from gm.api import *
import sys
try:
    from sklearn import svm
except:
    print('请安装scikit-learn库和带mkl的numpy')
    sys.exit(-1)
'''
本策略选取了七个特征变量组成了滑动窗口长度为15天的训练集,随后训练了一个二分类(上涨/下跌)的支持向量机模型.
若没有仓位则在每个星期一的时候输入标的股票近15个交易日的特征变量进行预测,并在预测结果为上涨的时候购买标的.
若已经持有仓位则在盈利大于10%的时候止盈,在星期五损失大于2%的时候止损.
特征变量为:1.收盘价/均值2.现量/均量3.最高价/均价4.最低价/均价5.现量6.区间收益率7.区间标准差
训练数据为:SHSE.600000浦发银行,时间从2016-03-01到2017-06-30
回测时间为:2017-07-01 09:00:00到2017-10-01 09:00:00
'''
def init(context):
    # 订阅浦发银行的分钟bar行情
    context.symbol = 'SHSE.600000'
    subscribe(symbols=context.symbol, frequency='60s')
    start_date = '2016-03-01'  # SVM训练起始时间
    end_date = '2017-06-30'  # SVM训练终止时间
    # 用于记录工作日
    # 获取目标股票的daily历史行情
    recent_data = history(context.symbol, frequency='1d', start_time=start_date, end_time=end_date, fill_missing='last',
                          df=True)
    days_value = recent_data['bob'].values
    days_close = recent_data['close'].values
    days = []
    # 获取行情日期列表
    print('准备数据训练SVM')
    for i in range(len(days_value)):
        days.append(str(days_value[i])[0:10])
    x_all = []
    y_all = []
    for index in range(15, (len(days) - 5)):
        # 计算三星期共15个交易日相关数据
        start_day = days[index - 15]
        end_day = days[index]
        data = history(context.symbol, frequency='1d', start_time=start_day, end_time=end_day, fill_missing='last',
                       df=True)
        close = data['close'].values
        max_x = data['high'].values
        min_n = data['low'].values
        amount = data['amount'].values
        volume = []
        for i in range(len(close)):
            volume_temp = amount[i] / close[i]
            volume.append(volume_temp)
        close_mean = close[-1] / np.mean(close)  # 收盘价/均值
        volume_mean = volume[-1] / np.mean(volume)  # 现量/均量
        max_mean = max_x[-1] / np.mean(max_x)  # 最高价/均价
        min_mean = min_n[-1] / np.mean(min_n)  # 最低价/均价
        vol = volume[-1]  # 现量
        return_now = close[-1] / close[0]  # 区间收益率
        std = np.std(np.array(close), axis=0)  # 区间标准差
        # 将计算出的指标添加到训练集X
        # features用于存放因子
        features = [close_mean, volume_mean, max_mean, min_mean, vol, return_now, std]
        x_all.append(features)
    # 准备算法需要用到的数据
    for i in range(len(days_close) - 20):
        if days_close[i + 20] > days_close[i + 15]:
            label = 1
        else:
            label = 0
        y_all.append(label)
    x_train = x_all[: -1]
    y_train = y_all[: -1]
    # 训练SVM
    context.clf = svm.SVC(C=1.0, kernel='rbf', degree=3, gamma='auto', coef0=0.0, shrinking=True, probability=False,
                          tol=0.001, cache_size=200, verbose=False, max_iter=-1,
                          decision_function_shape='ovr', random_state=None)
    context.clf.fit(x_train, y_train)
    print('训练完成!')
def on_bar(context, bars):
    bar = bars[0]
    # 获取当前年月日
    today = bar.bob.strftime('%Y-%m-%d')
    # 获取数据并计算相应的因子
    # 于星期一的09:31:00进行操作
    # 当前bar的工作日
    weekday = datetime.strptime(today, '%Y-%m-%d').isoweekday()
    # 获取模型相关的数据
    # 获取持仓
    position = context.account().position(symbol=context.symbol, side=PositionSide_Long)
    # 如果bar是新的星期一且没有仓位则开始预测
    if not position and weekday == 1:
        # 获取预测用的历史数据
        data = history_n(symbol=context.symbol, frequency='1d', end_time=today, count=15,
                         fill_missing='last', df=True)
        close = data['close'].values
        train_max_x = data['high'].values
        train_min_n = data['low'].values
        train_amount = data['amount'].values
        volume = []
        for i in range(len(close)):
            volume_temp = train_amount[i] / close[i]
            volume.append(volume_temp)
        close_mean = close[-1] / np.mean(close)
        volume_mean = volume[-1] / np.mean(volume)
        max_mean = train_max_x[-1] / np.mean(train_max_x)
        min_mean = train_min_n[-1] / np.mean(train_min_n)
        vol = volume[-1]
        return_now = close[-1] / close[0]
        std = np.std(np.array(close), axis=0)
        # 得到本次输入模型的因子
        features = [close_mean, volume_mean, max_mean, min_mean, vol, return_now, std]
        features = np.array(features).reshape(1, -1)
        prediction = context.clf.predict(features)[0]
        # 若预测值为上涨则开仓
        if prediction == 1:
            # 获取昨收盘价
            context.price = close[-1]
            # 把浦发银行的仓位调至95%
            order_target_percent(symbol=context.symbol, percent=0.95, order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print('SHSE.600000以市价单开多仓到仓位0.95')
    # 当涨幅大于10%,平掉所有仓位止盈
    elif position and bar.close / context.price >= 1.10:
        order_close_all()
        print('SHSE.600000以市价单全平多仓止盈')
    # 当时间为周五并且跌幅大于2%时,平掉所有仓位止损
    elif position and bar.close / context.price < 1.02 and weekday == 5:
        order_close_all()
        print('SHSE.600000以市价单全平多仓止损')
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-07-01 09:00:00',
        backtest_end_time='2017-10-01 09:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

7.配对交易

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
from gm.api import *
import  numpy as np



def init(context):
    #获得N日股票交易数据
    context.N=5
    #选择一对股票
    context.stock=['SZSE.000651','SZSE.000333']
    # 每个交易日的09:40 定时执行algo任务
    schedule(schedule_func=algo, date_rule='1d', time_rule='09:40:00')



def algo(context):
    # 获取上一个交易日的日期
    last_day = get_previous_trading_date(exchange='SHSE', date=context.now)
    # 获取当天有交易的股票,似乎无法同时获得两只股票的数据,所以只能麻烦一点
    not_suspended = get_history_instruments(symbols=context.stock[0], start_date=last_day, end_date=last_day)
    a = len([item['symbol'] for item in not_suspended if not item['is_suspended']])
    not_suspended = get_history_instruments(symbols=context.stock[1], start_date=last_day,end_date=last_day)
    b = len([item['symbol'] for item in not_suspended if not item['is_suspended']])
    #如果有一支停牌,就跳过
    if a+b<2:
        return
    #获得交易数据
    prices1 = history_n(symbol=context.stock[0], frequency='1d', count=context.N, end_time=last_day, fields='close',
                       skip_suspended=True,
                       fill_missing=None, adjust=ADJUST_PREV, adjust_end_time='', df=True)
    prices2=history_n(symbol=context.stock[1], frequency='1d', count=context.N, end_time=last_day, fields='close',
                       skip_suspended=True,
                       fill_missing=None, adjust=ADJUST_PREV, adjust_end_time='', df=True)
    p1=list(prices1['close'])
    p2=list(prices2['close'])
    spread = np.array(p1[:-1]) - np.array(p2[:-1])
    # 计算布林带的上下轨
    up = np.mean(spread) + 2 * np.std(spread)
    down = np.mean(spread) - 2 * np.std(spread)
    # 计算最新价差
    spread_now = p1[-1] - p2[-1]
    # 无交易时若价差上(下)穿布林带上(下)轨则做空(多)价差
    position_s1_long = context.account().position(symbol=context.stock[0], side=PositionSide_Long)
    position_s2_long = context.account().position(symbol=context.stock[1], side=PositionSide_Long)
    if not position_s1_long and not position_s2_long:
        if spread_now > up:
            order_target_percent(symbol=context.stock[1], percent=0.5, order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
        if spread_now < down:
            order_target_percent(symbol=context.stock[0], percent=0.5, order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            # 价差回归时平仓
    elif position_s2_long:
        if spread_now <= up:
            order_close_all()
    elif position_s1_long:
        if spread_now >= down:
            order_close_all()


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回测滑点比例
    '''
    run(strategy_id='73bb5bf2-a536-11e8-bd52-9cd21ef04ea9',
        filename='配对交易.py',
        mode=MODE_BACKTEST,
        token='c395247a76e8a5caeee699d668d6f550213bc418',
        backtest_start_time='2014-01-01 08:00:00',
        backtest_end_time='2018-08-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

8.GARP策略

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
from gm.api import *
from sklearn import preprocessing

'''
策略思路:
1、公司的资产负债率小于等于 25%
2、公司每股净现金大于 0
3、当前股价与每股自由现金流量比小于 10(市现率)
4、在所有股票中取市盈率排倒数30%的股票(首先PE必须大于0)
5、PEG=市盈率/净利润增长率<0.5
回测数据:SHSE.000906的成份股
回测时间:2016-01-01 08:00:00到2018-01-01 16:00:00
'''


def init(context):
    # 每月第一个交易日的09:40 定时执行algo任务
    schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')


def algo(context):
    # 获取上一个交易日的日期
    last_day = get_previous_trading_date(exchange='SHSE', date=context.now)
    # 获取沪深300成份股
    stock800 = get_history_constituents(index='SHSE.000906', start_date=last_day,
                                                end_date=last_day)[0]['constituents'].keys()
    # 获取当天有交易的股票
    not_suspended = get_history_instruments(symbols=stock800, start_date=last_day, end_date=last_day)
    not_suspended = [item['symbol'] for item in not_suspended if not item['is_suspended']]
    df = get_fundamentals(table='deriv_finance_indicator', symbols=not_suspended, start_date=last_day, end_date=last_day,
                           fields='ASSLIABRT,NCFPS,NPGRT', df=True)
    fin=get_fundamentals(table='trading_derivative_indicator', symbols=not_suspended, start_date=last_day, end_date=last_day,
                           fields='PCLFY,PELFY', df=True)
    df['PCLFY']=fin['PCLFY']
    df['PELFY'] = fin['PELFY']

    # 除去空值
    df = df.dropna()
    df['PEG']=df['PELFY']/df['NPGRT']
    df.index=df.symbol
    del df['symbol'],df['pub_date'],df['end_date']
    print(df)
    # 选出PEG小于0.5的部分
    df = df[df['PEG'] < 0.5]
    # 选出债务总资产比小于0.25的部分
    df = df[df["ASSLIABRT"] < 25]
    # 选出每股净现金大于 0的部分
    df = df[df["NCFPS"] > 0]
    # 选出市盈率大于零的部分
    df = df[df['PELFY'] > 0]
    # 选出市现率小于10的部分
    df = df[df['PCLFY'] < 10]

    print(df)
    # 剔除市盈率较高的股票(即剔除3分位数以后的股票)

    if len(df)<4:
        symbols_pool = list(df.index)
    else:
        df = df[(df['PELFY'] < df['PELFY'].quantile(0.3))]
        symbols_pool = list(df.index)
    print(symbols_pool)
    order_close_all()

    long=len(symbols_pool)
    if long==0:
        return
    # 获取股票的权重
    percent = 1 / long
    # 买在标的池中的股票
    for symbol in symbols_pool:
        order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
                             position_side=PositionSide_Long)
        #print(symbol, '以市价单调多仓到仓位', percent)


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回测滑点比例
    '''
    run(strategy_id='73bb5bf2-a536-11e8-bd52-9cd21ef04ea9',
        filename='GARP.py',
        mode=MODE_BACKTEST,
        token='c395247a76e8a5caeee699d668d6f550213bc418',
        backtest_start_time='2016-01-01 08:00:00',
        backtest_end_time='2018-01-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

9.alpha对冲(股票+期货)

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
from gm.api import *
'''
本策略每隔1个月定时触发计算SHSE.000300成份股的过去的EV/EBITDA并选取EV/EBITDA大于0的股票
随后平掉排名EV/EBITDA不在最小的30的股票持仓并等权购买EV/EBITDA最小排名在前30的股票
并用相应的CFFEX.IF对应的真实合约等额对冲
回测数据为:SHSE.000300和他们的成份股和CFFEX.IF对应的真实合约
回测时间为:2017-07-01 08:00:00到2017-10-01 16:00:00
'''
def init(context):
    # 每月第一个交易日09:40:00的定时执行algo任务
    schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')
    # 设置开仓在股票和期货的资金百分比(期货在后面自动进行杠杆相关的调整)
    context.percentage_stock = 0.4
    context.percentage_futures = 0.4
def algo(context):
    # 获取当前时刻
    now = context.now
    # 获取上一个交易日
    last_day = get_previous_trading_date(exchange='SHSE', date=now)
    # 获取沪深300成份股
    stock300 = get_history_constituents(index='SHSE.000300', start_date=last_day,
                                                end_date=last_day)[0]['constituents'].keys()
    # 获取上一个工作日的CFFEX.IF对应的合约
    index_futures = get_continuous_contracts(csymbol='CFFEX.IF', start_date=last_day, end_date=last_day)[-1]['symbol']
    # 获取当天有交易的股票
    not_suspended_info = get_history_instruments(symbols=stock300, start_date=now, end_date=now)
    not_suspended_symbols = [item['symbol'] for item in not_suspended_info if not item['is_suspended']]
    # 获取成份股EV/EBITDA大于0并为最小的30个
    fin = get_fundamentals(table='tq_sk_finindic', symbols=not_suspended_symbols,
                           start_date=now, end_date=now, fields='EVEBITDA',
                           filter='EVEBITDA>0', order_by='EVEBITDA', limit=30, df=True)
    fin.index = fin.symbol
    # 获取当前仓位
    positions = context.account().positions()
    # 平不在标的池或不为当前股指期货主力合约对应真实合约的标的
    for position in positions:
        symbol = position['symbol']
        sec_type = get_instrumentinfos(symbols=symbol)[0]['sec_type']
        # 若类型为期货且不在标的池则平仓
        if sec_type == SEC_TYPE_FUTURE and symbol != index_futures:
            order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
                                 position_side=PositionSide_Short)
            print('市价单平不在标的池的', symbol)
        elif symbol not in fin.index:
            order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print('市价单平不在标的池的', symbol)
    # 获取股票的权重
    percent = context.percentage_stock / len(fin.index)
    # 买在标的池中的股票
    for symbol in fin.index:
        order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
                             position_side=PositionSide_Long)
        print(symbol, '以市价单调多仓到仓位', percent)
    # 获取股指期货的保证金比率
    ratio = get_history_instruments(symbols=index_futures, start_date=last_day, end_date=last_day)[0]['margin_ratio']
    # 更新股指期货的权重
    percent = context.percentage_futures * ratio
    # 买入股指期货对冲
    order_target_percent(symbol=index_futures, percent=percent, order_type=OrderType_Market,
                         position_side=PositionSide_Short)
    print(index_futures, '以市价单调空仓到仓位', percent)
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-07-01 08:00:00',
        backtest_end_time='2017-10-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

二、期货策略

1.双均线策略

# coding=utf-8
from __future__ import print_function, absolute_import
from gm.api import *
import talib
import time
'''
本策略以DCE.i1801为交易标的,根据其一分钟(即60s频度)bar数据建立双均线模型,
短周期为30,长周期为60,当短期均线由上向下穿越长期均线时做空,
当短期均线由下向上穿越长期均线时做多,每次开仓前先平掉所持仓位,再开仓。
回测数据为:DCE.i1801的60s频度bar数据
回测时间为:2017-09-01 09:00:00到2017-09-30 15:00:00
'''
def init(context):
    context.FAST = 30                                              # 短周期
    context.SLOW = 60                                              # 长周期
    context.symbol = 'DCE.i1801'                                   # 订阅&交易标的
    context.period = context.SLOW + 1                              # 订阅数据滑窗长度
    subscribe(context.symbol, '60s', count=context.period)         # 订阅行情
def on_bar(context, bars):
    print (bars[0].bob)
    # 获取数据
    prices = context.data('DCE.i1801', '60s', context.period, fields='close')
    # 计算长短周期均线
    fast_avg = talib.SMA(prices.values.reshape(context.period), context.FAST)
    slow_avg = talib.SMA(prices.values.reshape(context.period), context.SLOW)
    # 均线下穿,做空
    if slow_avg[-2] < fast_avg[-2] and slow_avg[-1] >= fast_avg[-1]:
      # 平多仓
        order_target_percent(symbol=context.symbol, percent=0, position_side=1, order_type=2)
      # 开空仓
        order_target_percent(symbol=context.symbol, percent=0.1, position_side=2, order_type=2) 
    # 均线上穿,做多
    if fast_avg[-2] < slow_avg[-2] and fast_avg[-1] >= slow_avg[-1]:
      # 平空仓
        order_target_percent(symbol=context.symbol, percent=0, position_side=2,order_type=2) 
      # 开多仓
        order_target_percent(symbol=context.symbol, percent=0.1, position_side=1,order_type=2) 
def on_execution_report(context, execrpt):
    # 打印委托执行回报
    print(execrpt)  
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-09-01 09:00:00',
        backtest_end_time='2017-09-30 15:00:00',
        backtest_adjust=ADJUST_NONE,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

2.网格交易

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
import numpy as np
import pandas as pd
from gm.api import *
'''
本策略首先计算了过去300个价格数据的均值和标准差
并根据均值加减1和2个标准差得到网格的区间分界线,
并分别配以0.3和0.5的仓位权重
然后根据价格所在的区间来配置仓位(+/-40为上下界,无实际意义):
(-40,-3],(-3,-2],(-2,2],(2,3],(3,40](具体价格等于均值+数字倍标准差)
[-0.5, -0.3, 0.0, 0.3, 0.5](资金比例,此处负号表示开空仓)
回测数据为:SHFE.rb1801的1min数据
回测时间为:2017-07-01 08:00:00到2017-10-01 16:00:00
'''
def init(context):
    context.symbol = 'SHFE.rb1801'
    # 订阅SHFE.rb1801, bar频率为1min
    subscribe(symbols=context.symbol, frequency='60s')
    # 获取过去300个价格数据
    timeseries = history_n(symbol=context.symbol, frequency='60s', count=300, fields='close', fill_missing='Last',
                           end_time='2017-07-01 08:00:00', df=True)['close'].values
    # 获取网格区间分界线
    context.band = np.mean(timeseries) + np.array([-40, -3, -2, 2, 3, 40]) * np.std(timeseries)
    # 设置网格的仓位
    context.weight = [0.5, 0.3, 0.0, 0.3, 0.5]
def on_bar(context, bars):
    bar = bars[0]
    # 根据价格落在(-40,-3],(-3,-2],(-2,2],(2,3],(3,40]的区间范围来获取最新收盘价所在的价格区间
    grid = pd.cut([bar.close], context.band, labels=[0, 1, 2, 3, 4])[0]
    # 获取多仓仓位
    position_long = context.account().position(symbol=context.symbol, side=PositionSide_Long)
    # 获取空仓仓位
    position_short = context.account().position(symbol=context.symbol, side=PositionSide_Short)
    # 若无仓位且价格突破则按照设置好的区间开仓
    if not position_long and not position_short and grid != 2:
        # 大于3为在中间网格的上方,做多
        if grid >= 3:
            order_target_percent(symbol=context.symbol, percent=context.weight[grid], order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print(context.symbol, '以市价单开多仓到仓位', context.weight[grid])
        if grid <= 1:
            order_target_percent(symbol=context.symbol, percent=context.weight[grid], order_type=OrderType_Market,
                                 position_side=PositionSide_Short)
            print(context.symbol, '以市价单开空仓到仓位', context.weight[grid])
    # 持有多仓的处理
    elif position_long:
        if grid >= 3:
            order_target_percent(symbol=context.symbol, percent=context.weight[grid], order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print(context.symbol, '以市价单调多仓到仓位', context.weight[grid])
        # 等于2为在中间网格,平仓
        elif grid == 2:
            order_target_percent(symbol=context.symbol, percent=0, order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print(context.symbol, '以市价单全平多仓')
        # 小于1为在中间网格的下方,做空
        elif grid <= 1:
            order_target_percent(symbol=context.symbol, percent=0, order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print(context.symbol, '以市价单全平多仓')
            order_target_percent(symbol=context.symbol, percent=context.weight[grid], order_type=OrderType_Market,
                                 position_side=PositionSide_Short)
            print(context.symbol, '以市价单开空仓到仓位', context.weight[grid])
    # 持有空仓的处理
    elif position_short:
        # 小于1为在中间网格的下方,做空
        if grid <= 1:
            order_target_percent(symbol=context.symbol, percent=context.weight[grid], order_type=OrderType_Market,
                                 position_side=PositionSide_Short)
            print(context.symbol, '以市价单调空仓到仓位', context.weight[grid])
        # 等于2为在中间网格,平仓
        elif grid == 2:
            order_target_percent(symbol=context.symbol, percent=0, order_type=OrderType_Market,
                                 position_side=PositionSide_Short)
            print(context.symbol, '以市价单全平空仓')
        # 大于3为在中间网格的上方,做多
        elif grid >= 3:
            order_target_percent(symbol=context.symbol, percent=0, order_type=OrderType_Market,
                                 position_side=PositionSide_Short)
            print(context.symbol, '以市价单全平空仓')
            order_target_percent(symbol=context.symbol, percent=context.weight[grid], order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print(context.symbol, '以市价单开多仓到仓位', context.weight[grid])
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-07-01 08:00:00',
        backtest_end_time='2017-10-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

 3.跨品种套利

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
from gm.api import *
import numpy as np
'''
本策略根据计算滚动的.过去的30个1min的bar的均值正负2个标准差得到布林线
并在最新价差上穿上轨来做空价差,下穿下轨来做多价差
并在回归至上下轨水平内的时候平仓
回测数据为:SHFE.rb1801和SHFE.hc1801的1min数据
回测时间为:2017-09-01 08:00:00到2017-10-01 16:00:00
'''
def init(context):
    # 进行套利的品种
    context.goods = ['SHFE.rb1801', 'SHFE.hc1801']
    # 订阅行情
    subscribe(symbols=context.goods, frequency='60s', count=31, wait_group=True)
def on_bar(context, bars):
    # 获取两个品种的时间序列
    data_rb = context.data(symbol=context.goods[0], frequency='60s', count=31, fields='close')
    close_rb = data_rb.values
    data_hc = context.data(symbol=context.goods[1], frequency='60s', count=31, fields='close')
    close_hc = data_hc.values
    # 计算价差
    spread = close_rb[:-1] - close_hc[:-1]
    # 计算布林带的上下轨
    up = np.mean(spread) + 2 * np.std(spread)
    down = np.mean(spread) - 2 * np.std(spread)
    # 计算最新价差
    spread_now = close_rb[-1] - close_hc[-1]
    # 无交易时若价差上(下)穿布林带上(下)轨则做空(多)价差
    position_rb_long = context.account().position(symbol=context.goods[0], side=PositionSide_Long)
    position_rb_short = context.account().position(symbol=context.goods[0], side=PositionSide_Short)
    if not position_rb_long and not position_rb_short:
        if spread_now > up:
            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Short)
            print(context.goods[0], '以市价单开空仓一手')
            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Long)
            print(context.goods[1], '以市价单开多仓一手')
        if spread_now < down:
            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Long)
            print(context.goods[0], '以市价单开多仓一手')
            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Short)
            print(context.goods[1], '以市价单开空仓一手')
    # 价差回归时平仓
    elif position_rb_short:
        if spread_now <= up:
            order_close_all()
            print('价格回归,平所有仓位')
            # 跌破下轨反向开仓
        if spread_now < down:
            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Long)
            print(context.goods[0], '以市价单开多仓一手')
            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Short)
            print(context.goods[1], '以市价单开空仓一手')
    elif position_rb_long:
        if spread_now >= down:
            order_close_all()
            print('价格回归,平所有仓位')
            # 涨破上轨反向开仓
        if spread_now > up:
            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Short)
            print(context.goods[0], '以市价单开空仓一手')
            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Long)
            print(context.goods[1], '以市价单开多仓一手')
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-09-01 08:00:00',
        backtest_end_time='2017-10-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=500000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

4.跨期套利

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
import numpy as np
from gm.api import *
try:
    import statsmodels.tsa.stattools as ts
except:
    print('请安装statsmodels库')
'''
本策略根据EG两步法(1.序列同阶单整2.OLS残差平稳)判断序列具有协整关系之后(若无协整关系则全平仓位不进行操作)
通过计算两个真实价格序列回归残差的0.9个标准差上下轨,并在价差突破上轨的时候做空价差,价差突破下轨的时候做多价差
并在回归至标准差水平内的时候平仓
回测数据为:SHFE.rb1801和SHFE.rb1805的1min数据
回测时间为:2017-09-25 08:00:00到2017-10-01 15:00:00
'''
# 协整检验的函数
def cointegration_test(series01, series02):
    urt_rb1801 = ts.adfuller(np.array(series01), 1)[1]
    urt_rb1805 = ts.adfuller(np.array(series01), 1)[1]
    # 同时平稳或不平稳则差分再次检验
    if (urt_rb1801 > 0.1 and urt_rb1805 > 0.1) or (urt_rb1801 < 0.1 and urt_rb1805 < 0.1):
        urt_diff_rb1801 = ts.adfuller(np.diff(np.array(series01)), 1)[1]
        urt_diff_rb1805 = ts.adfuller(np.diff(np.array(series01), 1))[1]
        # 同时差分平稳进行OLS回归的残差平稳检验
        if urt_diff_rb1801 < 0.1 and urt_diff_rb1805 < 0.1:
            matrix = np.vstack([series02, np.ones(len(series02))]).T
            beta, c = np.linalg.lstsq(matrix, series01)[0]
            resid = series01 - beta * series02 - c
            if ts.adfuller(np.array(resid), 1)[1] > 0.1:
                result = 0.0
            else:
                result = 1.0
            return beta, c, resid, result
        else:
            result = 0.0
            return 0.0, 0.0, 0.0, result
    else:
        result = 0.0
        return 0.0, 0.0, 0.0, result
def init(context):
    context.goods = ['SHFE.rb1801', 'SHFE.rb1805']
    # 订阅品种
    subscribe(symbols=context.goods, frequency='60s', count=801, wait_group=True)
def on_bar(context, bars):
    # 获取过去800个60s的收盘价数据
    close_01 = context.data(symbol=context.goods[0], frequency='60s', count=801, fields='close')['close'].values
    close_02 = context.data(symbol=context.goods[1], frequency='60s', count=801, fields='close')['close'].values
    # 展示两个价格序列的协整检验的结果
    beta, c, resid, result = cointegration_test(close_01, close_02)
    # 如果返回协整检验不通过的结果则全平仓位等待
    if not result:
        print('协整检验不通过,全平所有仓位')
        order_close_all()
        return
    # 计算残差的标准差上下轨
    mean = np.mean(resid)
    up = mean + 0.9 * np.std(resid)
    down = mean - 0.9 * np.std(resid)
    # 计算新残差
    resid_new = close_01[-1] - beta * close_02[-1] - c
    # 获取rb1801的多空仓位
    position_01_long = context.account().position(symbol=context.goods[0], side=PositionSide_Long)
    position_01_short = context.account().position(symbol=context.goods[0], side=PositionSide_Short)
    if not position_01_long and not position_01_short:
        # 上穿上轨时做空新残差
        if resid_new > up:
            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Short)
            print(context.goods[0] + '以市价单开空仓1手')
            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Long)
            print(context.goods[1] + '以市价单开多仓1手')
        # 下穿下轨时做多新残差
        if resid_new < down:
            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Long)
            print(context.goods[0], '以市价单开多仓1手')
            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Short)
            print(context.goods[1], '以市价单开空仓1手')
    # 新残差回归时平仓
    elif position_01_short:
        if resid_new <= up:
            order_close_all()
            print('价格回归,平掉所有仓位')
        # 突破下轨反向开仓
        if resid_new < down:
            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Long)
            print(context.goods[0], '以市价单开多仓1手')
            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Short)
            print(context.goods[1], '以市价单开空仓1手')
    elif position_01_long:
        if resid_new >= down:
            order_close_all()
            print('价格回归,平所有仓位')
        # 突破上轨反向开仓
        if resid_new > up:
            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Short)
            print(context.goods[0], '以市价单开空仓1手')
            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,
                                position_side=PositionSide_Long)
            print(context.goods[1], '以市价单开多仓1手')
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-09-25 08:00:00',
        backtest_end_time='2017-10-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=500000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

5.海龟交易法

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
import numpy as np
import pandas as pd
try:
    import talib
except:
    print('请安装TA-Lib库')
from gm.api import *
'''
本策略通过计算CZCE.FG801和SHFE.rb1801的ATR.唐奇安通道和MA线,并:
上穿唐奇安通道且短MA在长MA上方则开多仓,下穿唐奇安通道且短MA在长MA下方则开空仓
若有 多/空 仓位则分别:
价格 跌/涨 破唐奇安平仓通道 上/下 轨则全平仓位,否则
根据 跌/涨 破持仓均价 -/+ x(x=0.5,1,1.5,2)倍ATR把仓位
回测数据为:CZCE.FG801和SHFE.rb1801的1min数据
回测时间为:2017-09-15 09:15:00到2017-10-01 15:00:00
'''
def init(context):
    # context.parameter分别为唐奇安开仓通道.唐奇安平仓通道.短ma.长ma.ATR的参数
    context.parameter = [55, 20, 10, 60, 20]
    context.tar = context.parameter[4]
    # context.goods交易的品种
    context.goods = ['CZCE.FG801', 'SHFE.rb1801']
    # context.ratio交易最大资金比率
    context.ratio = 0.8
    # 订阅context.goods里面的品种, bar频率为1min
    subscribe(symbols=context.goods, frequency='60s', count=101)
    # 止损的比例区间
def on_bar(context, bars):
    bar = bars[0]
    symbol = bar['symbol']
    recent_data = context.data(symbol=symbol, frequency='60s', count=101, fields='close,high,low')
    close = recent_data['close'].values[-1]
    # 计算ATR
    atr = talib.ATR(recent_data['high'].values, recent_data['low'].values, recent_data['close'].values,
                    timeperiod=context.tar)[-1]
    # 计算唐奇安开仓和平仓通道
    context.don_open = context.parameter[0] + 1
    upper_band = talib.MAX(recent_data['close'].values[:-1], timeperiod=context.don_open)[-1]
    context.don_close = context.parameter[1] + 1
    lower_band = talib.MIN(recent_data['close'].values[:-1], timeperiod=context.don_close)[-1]
    # 计算开仓的资金比例
    percent = context.ratio / float(len(context.goods))
    # 若没有仓位则开仓
    position_long = context.account().position(symbol=symbol, side=PositionSide_Long)
    position_short = context.account().position(symbol=symbol, side=PositionSide_Short)
    if not position_long and not position_short:
        # 计算长短ma线.DIF
        ma_short = talib.MA(recent_data['close'].values, timeperiod=(context.parameter[2] + 1))[-1]
        ma_long = talib.MA(recent_data['close'].values, timeperiod=(context.parameter[3] + 1))[-1]
        dif = ma_short - ma_long
        # 获取当前价格
        # 上穿唐奇安通道且短ma在长ma上方则开多仓
        if close > upper_band and (dif > 0):
            order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
                                 position_side=PositionSide_Long)
            print(symbol, '市价单开多仓到比例: ', percent)
        # 下穿唐奇安通道且短ma在长ma下方则开空仓
        if close < lower_band and (dif < 0):
            order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
                                 position_side=PositionSide_Short)
            print(symbol, '市价单开空仓到比例: ', percent)
    elif position_long:
        # 价格跌破唐奇安平仓通道全平仓位止损
        if close < lower_band:
            order_close_all()
            print(symbol, '市价单全平仓位')
        else:
            # 获取持仓均价
            vwap = position_long['vwap']
            # 获取持仓的资金
            money = position_long['cost']
            # 获取平仓的区间
            band = vwap - np.array([200, 2, 1.5, 1, 0.5, -100]) * atr
            grid_percent = float(pd.cut([close], band, labels=[0, 0.25, 0.5, 0.75, 1])[0]) * percent
            # 选择现有百分比和区间百分比中较小的值(避免开仓)
            target_percent = np.minimum(money / context.account().cash['nav'], grid_percent)
            if target_percent != 1.0:
                print(symbol, '市价单平多仓到比例: ', target_percent)
                order_target_percent(symbol=symbol, percent=target_percent, order_type=OrderType_Market,
                                     position_side=PositionSide_Long)
    elif position_short:
        # 价格涨破唐奇安平仓通道或价格涨破持仓均价加两倍ATR平空仓
        if close > upper_band:
            order_close_all()
            print(symbol, '市价单全平仓位')
        else:
            # 获取持仓均价
            vwap = position_short['vwap']
            # 获取持仓的资金
            money = position_short['cost']
            # 获取平仓的区间
            band = vwap + np.array([-100, 0.5, 1, 1.5, 2, 200]) * atr
            grid_percent = float(pd.cut([close], band, labels=[1, 0.75, 0.5, 0.25, 0])[0]) * percent
            # 选择现有百分比和区间百分比中较小的值(避免开仓)
            target_percent = np.minimum(money / context.account().cash['nav'], grid_percent)
            if target_percent != 1.0:
                order_target_percent(symbol=symbol, percent=target_percent, order_type=OrderType_Market,
                                     position_side=PositionSide_Short)
                print(symbol, '市价单平空仓到比例: ', target_percent)
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回测滑点比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-09-15 09:15:00',
        backtest_end_time='2017-10-01 15:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

6.做市商交易

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
from gm.api import *
'''
本策略通过不断对CZCE.CF801进行:
买(卖)一价现价单开多(空)仓和卖(买)一价平多(空)仓来做市
并以此赚取差价
回测数据为:CZCE.CF801的tick数据
回测时间为:2017-09-29 11:25:00到2017-09-29 11:30:00
需要特别注意的是:本平台对于回测对限价单固定完全成交,本例子 仅供参考.
敬请通过适当调整回测参数
1.backtest_commission_ratio回测佣金比例
2.backtest_slippage_ratio回测滑点比例
3.backtest_transaction_ratio回测成交比例
以及优化策略逻辑来达到更贴近实际的回测效果
'''
def init(context):
    # 订阅CZCE.CF801的tick数据
    context.symbol = 'CZCE.CF801'
    subscribe(symbols=context.symbol, frequency='tick')
def on_tick(context, tick):
    quotes = tick['quotes'][0]
    # 获取持有的多仓
    positio_long = context.account().position(symbol=context.symbol, side=PositionSide_Long)
    # 获取持有的空仓
    position_short = context.account().position(symbol=context.symbol, side=PositionSide_Short)
    print(quotes['bid_p'])
    print(quotes['ask_p'])
    # 没有仓位则双向开限价单
    # 若有仓位则限价单平仓
    if not positio_long:
        # 获取买一价
        price = quotes['bid_p']
        print('买一价为: ', price)
        order_target_volume(symbol=context.symbol, volume=1, price=price, order_type=OrderType_Limit,
                            position_side=PositionSide_Long)
        print('CZCE.CF801开限价单多仓1手')
    else:
        # 获取卖一价
        price = quotes['ask_p']
        print('卖一价为: ', price)
        order_target_volume(symbol=context.symbol, volume=0, price=price, order_type=OrderType_Limit,
                            position_side=PositionSide_Long)
        print('CZCE.CF801平限价单多仓1手')
    if not position_short:
        # 获取卖一价
        price = quotes['ask_p']
        print('卖一价为: ', price)
        order_target_volume(symbol=context.symbol, volume=1, price=price, order_type=OrderType_Limit,
                            position_side=PositionSide_Short)
        print('CZCE.CF801卖一价开限价单空仓')
    else:
        # 获取买一价
        price = quotes['bid_p']
        print('买一价为: ', price)
        order_target_volume(symbol=context.symbol, volume=0, price=price, order_type=OrderType_Limit,
                            position_side=PositionSide_Short)
        print('CZCE.CF801买一价平限价单空仓')
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_transaction_ratio回测成交比例
    '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token_id',
        backtest_start_time='2017-09-29 11:25:00',
        backtest_end_time='2017-09-29 11:30:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=500000,
        backtest_commission_ratio=0.00006,
        backtest_slippage_ratio=0.0001,
        backtest_transaction_ratio=0.5)

三、其他

1.MACD策略

# -*- coding: utf-8 -*-

# 简便起见,可以直接用 from gm.api import *
from gm.api import run
from gm.api import ADJUST_PREV
from gm.api import MODE_BACKTEST
from gm.api import subscribe
from gm.api import history_n
from gm.api import order_percent
from gm.api import order_volume
from gm.api import (OrderSide_Buy, OrderSide_Sell)
from gm.api import (PositionEffect_Open, PositionEffect_Close)
from gm.api import OrderType_Market
from datetime import datetime
from datetime import timedelta
import talib
import numpy as np
from collections import deque

# 常用参量设置
DATE_STR = "%Y-%m-%d"
TIME_STR = "%Y-%m-%d %H:%M:%S"

HIST_WINDOW = 40
SHORT_PERIOD = 5
LONG_PERIOD = 20

def init(context):
    # 全局变量设置
    context.dict_stock_price = dict()
    # 以 50 EFT作为交易标的
    context.stock_pool = ['SZSE.000001']
    # 订阅日线行情
    subscribe(symbols=context.stock_pool, frequency='1d', wait_group=True)
    # 日期设定,避免出现未来函数,将起始日往前取一日
    start_date = datetime.strptime(context.backtest_start_time, TIME_STR)
    context.start_date = datetime.strftime(start_date - timedelta(days=1),
                                           TIME_STR)
    # 获取起始日之前行情,便于计算指标
    deque_high = deque(maxlen=HIST_WINDOW)
    deque_low = deque(maxlen=HIST_WINDOW)
    deque_close = deque(maxlen=HIST_WINDOW)
    for stock in context.stock_pool:
        history_info = history_n(symbol=stock, 
                                 frequency='1d', 
                                 count=HIST_WINDOW,
                                 adjust=ADJUST_PREV,
                                 adjust_end_time=context.backtest_end_time,
                                 end_time=context.start_date,
                                 fields='high, low, close')
        for bar in history_info:
            deque_high.append(bar['high'])
            deque_low.append(bar['low'])
            deque_close.append(bar['close'])
        context.dict_stock_price.setdefault(stock, 
                                            [deque_high, deque_low, deque_close])
    print('finish initialization')
        
def on_bar(context, bars):
    for bar in bars:
        if bar.symbol not in context.dict_stock_price.keys():
            print('Warning: cannot obtain price of stock {} at date {}'.format(
                    bar.symbol, context.now))
        # 数据填充
        context.dict_stock_price[bar.symbol][0].append(bar.high)
        context.dict_stock_price[bar.symbol][1].append(bar.low)
        context.dict_stock_price[bar.symbol][2].append(bar.close)
        # 计算指标,这里以双均线为例
        # highs = np.array(context.dict_stock_price[bar.symbol][0])
        # lows = np.array(context.dict_stock_price[bar.symbol][1])
        closes = np.array(context.dict_stock_price[bar.symbol][2])
        macd, macd_signal, macd_hist = talib.MACD(closes, 
                                                  fastperiod=12, 
                                                  slowperiod=26, 
                                                  signalperiod=9)
        # 金叉,满仓买入
        if macd_hist[-2] <= 0 and macd_hist[-1] > 0:
            order_percent(symbol=bar.symbol,
                          percent=1.0,
                          side=OrderSide_Buy,
                          order_type=OrderType_Market,
                          position_effect=PositionEffect_Open,
                          price=0)
            print(context.now)
        # 死叉,全部卖出
        pos = context.account().position(symbol=bar.symbol, side=OrderSide_Buy)
        if (macd_hist[-2] >= 0 and macd_hist[-1] < 0):
            if pos is None:
                continue
            order_volume(symbol=bar.symbol,
                         volume=pos.volume,
                         side=OrderSide_Sell,
                         order_type=OrderType_Market,
                         position_effect=PositionEffect_Close,
                         price=0)
            
if __name__ == "__main__":
    run(strategy_id='569b4ffc-6d44-11e8-bd88-80ce62334e41',
        filename='demo_04.py',
        mode=MODE_BACKTEST,
        backtest_adjust=ADJUST_PREV,
        token='64c33fc82f334e11e1138eefea8ffc241db4a2a0',
        backtest_start_time='2017-01-17 09:00:00',
        backtest_end_time='2018-06-21 15:00:00')

2.KD策略

# -*- coding: utf-8 -*-

#本策略基于掘金量化交易平台 网址:www.myquant.cn

# 简便起见,可以直接用 from gm.api import *
from gm.api import run
from gm.api import ADJUST_PREV
from gm.api import MODE_BACKTEST
from gm.api import subscribe
from gm.api import history_n
from gm.api import order_percent
from gm.api import order_volume
from gm.api import (OrderSide_Buy, OrderSide_Sell)
from gm.api import (PositionEffect_Open, PositionEffect_Close)
from gm.api import OrderType_Market
from datetime import datetime
from datetime import timedelta
import talib
import numpy as np
from collections import deque

# 常用参量设置
DATE_STR = "%Y-%m-%d"
TIME_STR = "%Y-%m-%d %H:%M:%S"

HIST_WINDOW = 30
SHORT_PERIOD = 5
LONG_PERIOD = 20

def init(context):
    # 全局变量设置
    context.dict_stock_price = dict()
    # 以 50 EFT作为交易标的
    context.stock_pool = ['SZSE.000001']
    # 订阅日线行情
    subscribe(symbols=context.stock_pool, frequency='1d', wait_group=True)
    # 日期设定,避免出现未来函数,将起始日往前取一日
    start_date = datetime.strptime(context.backtest_start_time, TIME_STR)
    context.start_date = datetime.strftime(start_date - timedelta(days=1),
                                           TIME_STR)
    # 获取起始日之前行情,便于计算指标
    deque_high = deque(maxlen=HIST_WINDOW)
    deque_low = deque(maxlen=HIST_WINDOW)
    deque_close = deque(maxlen=HIST_WINDOW)
    for stock in context.stock_pool:
        history_info = history_n(symbol=stock, 
                                 frequency='1d', 
                                 count=HIST_WINDOW,
                                 adjust=ADJUST_PREV,
                                 adjust_end_time=context.backtest_end_time,
                                 end_time=context.start_date,
                                 fields='high, low, close')
        for bar in history_info:
            deque_high.append(bar['high'])
            deque_low.append(bar['low'])
            deque_close.append(bar['close'])
        context.dict_stock_price.setdefault(stock, 
                                            [deque_high, deque_low, deque_close])
    print('finish initialization')
        
def on_bar(context, bars):
    for bar in bars:
        if bar.symbol not in context.dict_stock_price.keys():
            print('Warning: cannot obtain price of stock {} at date {}'.format(
                    bar.symbol, context.now))
        # 数据填充
        context.dict_stock_price[bar.symbol][0].append(bar.high)
        context.dict_stock_price[bar.symbol][1].append(bar.low)
        context.dict_stock_price[bar.symbol][2].append(bar.close)
        # 计算指标,这里以双均线为例
        highs = np.array(context.dict_stock_price[bar.symbol][0])
        lows = np.array(context.dict_stock_price[bar.symbol][1])
        closes = np.array(context.dict_stock_price[bar.symbol][2])
        k_value, d_value = talib.STOCH(highs,
                                       lows,
                                       closes,
                                       fastk_period=9,
                                       slowk_period=3,
                                       slowk_matype=0,
                                       slowd_period=3,
                                       slowd_matype=0)
        # 金叉,满仓买入
        if k_value[-2] <= d_value[-2] and k_value[-1] > d_value[-1]:
            order_percent(symbol=bar.symbol,
                          percent=1.0,
                          side=OrderSide_Buy,
                          order_type=OrderType_Market,
                          position_effect=PositionEffect_Open,
                          price=0)
            print(context.now)
        # 死叉,全部卖出
        pos = context.account().position(symbol=bar.symbol, side=OrderSide_Buy)
        if k_value[-2] >= d_value[-2] and k_value[-1] < d_value[-1]:
            if pos is None:
                continue
            order_volume(symbol=bar.symbol,
                         volume=pos.volume,
                         side=OrderSide_Sell,
                         order_type=OrderType_Market,
                         position_effect=PositionEffect_Close,
                         price=0)
            
if __name__ == "__main__":
    run(strategy_id='569b4ffc-6d44-11e8-bd88-80ce62334e41',
        filename='demo_02.py',
        mode=MODE_BACKTEST,
        backtest_adjust=ADJUST_PREV,
        token='64c33fc82f334e11e1138eefea8ffc241db4a2a0',
        backtest_start_time='2017-01-17 09:00:00',
        backtest_end_time='2018-06-21 15:00:00')

3.双均线加上MACD过滤

# -*- coding: utf-8 -*-

# 简便起见,可以直接用 from gm.api import *
from gm.api import run
from gm.api import ADJUST_PREV
from gm.api import MODE_BACKTEST
from gm.api import subscribe
from gm.api import history_n
from gm.api import order_percent
from gm.api import order_volume
from gm.api import (OrderSide_Buy, OrderSide_Sell)
from gm.api import (PositionEffect_Open, PositionEffect_Close)
from gm.api import OrderType_Market
from datetime import datetime
from datetime import timedelta
import talib
import numpy as np
from collections import deque

# 常用参量设置
DATE_STR = "%Y-%m-%d"
TIME_STR = "%Y-%m-%d %H:%M:%S"

HIST_WINDOW = 40
SHORT_PERIOD = 5
LONG_PERIOD = 20

def init(context):
    # 全局变量设置
    context.dict_stock_price = dict()
    # 以 50 EFT作为交易标的
    context.stock_pool = ['SHSE.600000']
    # 订阅日线行情
    subscribe(symbols=context.stock_pool, frequency='1d', wait_group=True)
    # 日期设定,避免出现未来函数,将起始日往前取一日
    start_date = datetime.strptime(context.backtest_start_time, TIME_STR)
    context.start_date = datetime.strftime(start_date - timedelta(days=1),
                                           TIME_STR)
    # 获取起始日之前行情,便于计算指标
    deque_close = deque(maxlen=HIST_WINDOW)
    for stock in context.stock_pool:
        history_info = history_n(symbol=stock, 
                                 frequency='1d', 
                                 count=HIST_WINDOW,
                                 adjust=ADJUST_PREV,
                                 adjust_end_time=context.backtest_end_time,
                                 end_time=context.start_date,
                                 fields='close')
        for bar in history_info:
            deque_close.append(bar['close'])
        context.dict_stock_price.setdefault(stock, deque_close)
    print('finish initialization')
        
def on_bar(context, bars):
    for bar in bars:
        if bar.symbol not in context.dict_stock_price.keys():
            print('Warning: cannot obtain price of stock {} at date {}'.format(
                    bar.symbol, context.now))
        # 数据填充
        context.dict_stock_price[bar.symbol].append(bar.close)
        # 计算指标,这里以双均线为例
        closes = np.array(context.dict_stock_price[bar.symbol])
        short_ma = talib.SMA(closes, SHORT_PERIOD)
        long_ma = talib.SMA(closes, LONG_PERIOD)
        macd, macd_signal, macd_hist = talib.MACD(closes, 
                                                  fastperiod=12, 
                                                  slowperiod=26, 
                                                  signalperiod=9)
        # 金叉,满仓买入
        if short_ma[-2] <= long_ma[-2] and short_ma[-1] > long_ma[-1]:
            order_percent(symbol=bar.symbol,
                          percent=1.0,
                          side=OrderSide_Buy,
                          order_type=OrderType_Market,
                          position_effect=PositionEffect_Open,
                          price=0)
            print(context.now)
        # 死叉或者 MACD 绿柱,全部卖出
        pos = context.account().position(symbol=bar.symbol, side=OrderSide_Buy)
        if (short_ma[-2] >= long_ma[-2] and short_ma[-1] < long_ma[-1]) or \
            macd_hist[-1] < 0:
            if pos is None:
                continue
            order_volume(symbol=bar.symbol,
                         volume=pos.volume,
                         side=OrderSide_Sell,
                         order_type=OrderType_Market,
                         position_effect=PositionEffect_Close,
                         price=0)
if __name__ == "__main__":
    run(strategy_id='569b4ffc-6d44-11e8-bd88-80ce62334e41',
        filename='demo_05.py',
        mode=MODE_BACKTEST,
        backtest_adjust=ADJUST_PREV,
        token='64c33fc82f334e11e1138eefea8ffc241db4a2a0',
        backtest_start_time='2017-01-17 09:00:00',
        backtest_end_time='2018-06-21 15:00:00')

4.KDJ中J值策略

# -*- coding: utf-8 -*-

#本策略基于掘金量化交易平台 网址:www.myquant.cn

# 简便起见,可以直接用 from gm.api import *
from gm.api import run
from gm.api import ADJUST_PREV
from gm.api import MODE_BACKTEST
from gm.api import subscribe
from gm.api import history_n
from gm.api import order_percent
from gm.api import order_volume
from gm.api import (OrderSide_Buy, OrderSide_Sell)
from gm.api import (PositionEffect_Open, PositionEffect_Close)
from gm.api import OrderType_Market
from datetime import datetime
from datetime import timedelta
import talib
import numpy as np
from collections import deque

# 常用参量设置
DATE_STR = "%Y-%m-%d"
TIME_STR = "%Y-%m-%d %H:%M:%S"

HIST_WINDOW = 30
SHORT_PERIOD = 5
LONG_PERIOD = 20

def init(context):
    # 全局变量设置
    context.dict_stock_price = dict()
    # 以 50 EFT作为交易标的
    context.stock_pool = ['SZSE.00001']
    # 订阅日线行情
    subscribe(symbols=context.stock_pool, frequency='1d', wait_group=True)
    # 日期设定,避免出现未来函数,将起始日往前取一日
    start_date = datetime.strptime(context.backtest_start_time, TIME_STR)
    context.start_date = datetime.strftime(start_date - timedelta(days=1),
                                           TIME_STR)
    # 获取起始日之前行情,便于计算指标
    deque_high = deque(maxlen=HIST_WINDOW)
    deque_low = deque(maxlen=HIST_WINDOW)
    deque_close = deque(maxlen=HIST_WINDOW)
    for stock in context.stock_pool:
        history_info = history_n(symbol=stock, 
                                 frequency='1d', 
                                 count=HIST_WINDOW,
                                 adjust=ADJUST_PREV,
                                 adjust_end_time=context.backtest_end_time,
                                 end_time=context.start_date,
                                 fields='high, low, close')
        for bar in history_info:
            deque_high.append(bar['high'])
            deque_low.append(bar['low'])
            deque_close.append(bar['close'])
        context.dict_stock_price.setdefault(stock, 
                                            [deque_high, deque_low, deque_close])
    print('finish initialization')
        
def on_bar(context, bars):
    for bar in bars:
        if bar.symbol not in context.dict_stock_price.keys():
            print('Warning: cannot obtain price of stock {} at date {}'.format(
                    bar.symbol, context.now))
        # 数据填充
        context.dict_stock_price[bar.symbol][0].append(bar.high)
        context.dict_stock_price[bar.symbol][1].append(bar.low)
        context.dict_stock_price[bar.symbol][2].append(bar.close)
        # 计算指标,这里以双均线为例
        highs = np.array(context.dict_stock_price[bar.symbol][0])
        lows = np.array(context.dict_stock_price[bar.symbol][1])
        closes = np.array(context.dict_stock_price[bar.symbol][2])
        k_value, d_value = talib.STOCH(highs,
                                       lows,
                                       closes,
                                       fastk_period=9,
                                       slowk_period=3,
                                       slowk_matype=0,
                                       slowd_period=3,
                                       slowd_matype=0)
        j_value = 3*k_value - 2*d_value
        # 金叉,满仓买入
        if j_value[-1] >= 80 or j_value[-1] <= 20:
            order_percent(symbol=bar.symbol,
                          percent=1.0,
                          side=OrderSide_Buy,
                          order_type=OrderType_Market,
                          position_effect=PositionEffect_Open,
                          price=0)
            print(context.now)
        # 死叉,全部卖出
        pos = context.account().position(symbol=bar.symbol, side=OrderSide_Buy)
        if (j_value[-1] < 80 and j_value[-1] > 20):
            if pos is None:
                continue
            order_volume(symbol=bar.symbol,
                         volume=pos.volume,
                         side=OrderSide_Sell,
                         order_type=OrderType_Market,
                         position_effect=PositionEffect_Close,
                         price=0)
            
if __name__ == "__main__":
    run(strategy_id='569b4ffc-6d44-11e8-bd88-80ce62334e41',
        filename='demo_03.py',
        mode=MODE_BACKTEST,
        backtest_adjust=ADJUST_PREV,
        token='64c33fc82f334e11e1138eefea8ffc241db4a2a0',
        backtest_start_time='2017-01-17 09:00:00',
        backtest_end_time='2018-06-21 15:00:00')

5.RSRS标准分

from __future__ import print_function, absolute_import
from gm.api import *
import statsmodels.api as  sm
import numpy as np


def init(context):
    # 设置参数
    context.N=18
    context.M=600
    context.ans=[]
    context.buy=0.7
    context.sell=-0.7
    #获取历史数据及历史斜率
    prices = history_n(symbol='SHSE.000300', frequency='1d', count=context.M, end_time='2014-01-01', fields='high,low',skip_suspended=True,
                    fill_missing=None,adjust=ADJUST_PREV,df=True)
    highs = prices.high
    lows = prices.low
    context.ans = []
    for i in range(len(highs))[context.N:]:
        data_high = highs.iloc[i - context.N + 1:i + 1]
        data_low = lows.iloc[i - context.N + 1:i + 1]
        X = sm.add_constant(data_low)
        model = sm.OLS(data_high, X)
        results = model.fit()
        context.ans.append(results.params[1])
    schedule(schedule_func=algo, date_rule='1d', time_rule='09:40:00')


def algo(context):
    # 获取上一个交易日的日期
    last_day = get_previous_trading_date(exchange='SHSE', date=context.now)
    # 计算前一日的RSRS斜率
    prices = history_n(symbol='SHSE.000300', frequency='1d', count=context.N, end_time=last_day, fields='', skip_suspended=True,
                       fill_missing=None, adjust=ADJUST_PREV, adjust_end_time='', df=True)
    #做回归计算
    highs = prices.high
    lows = prices.low
    X = sm.add_constant(lows)
    model = sm.OLS(highs, X)
    results = model.fit()
    context.ans.append(results.params[1])

    # 计算标准化的RSRS指标
    # 计算均值序列
    section = context.ans[-context.M:]
    # 计算均值序列
    mu = np.mean(section)
    # 计算标准化RSRS指标序列
    sigma = np.std(section)
    zscore = (section[-1] - mu) / sigma
    if zscore > context.buy:
        order_target_percent(symbol='SHSE.000300', percent=1, order_type=OrderType_Market,
                             position_side=PositionSide_Long)

    if zscore < context.sell:
        order_close_all()



if __name__ == '__main__':
    run(strategy_id='73bb5bf2-a536-11e8-bd52-9cd21ef04ea9',
        filename='RSRS.py',
        mode=MODE_BACKTEST,
        token='c395247a76e8a5caeee699d668d6f550213bc418',
        backtest_start_time='2014-01-01 08:00:00',
        backtest_end_time='2018-01-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0,
        backtest_slippage_ratio=0)

6.RSRS斜率

from __future__ import print_function, absolute_import
from gm.api import *
import statsmodels.api as  sm
import numpy as np


def init(context):
    #设置参数
    context.N=18
    context.M=3600
    context.ans=[]
    #获取历史数据及历史斜率
    prices = history_n(symbol='SHSE.000300', frequency='1d', count=context.M, end_time='2014-01-01', fields='high,low',skip_suspended=True,
                    fill_missing=None,adjust=ADJUST_PREV,df=True)
    highs = prices.high
    lows = prices.low
    context.ans = []
    for i in range(len(highs))[context.N:]:
        data_high = highs.iloc[i - context.N + 1:i + 1]
        data_low = lows.iloc[i - context.N + 1:i + 1]
        X = sm.add_constant(data_low)
        model = sm.OLS(data_high, X)
        results = model.fit()
        context.ans.append(results.params[1])
    mu=np.mean(context.ans)
    sigama=np.std(context.ans)
    #求阈值
    context.buy=mu+sigama
    context.sell=mu-sigama
    schedule(schedule_func=algo, date_rule='1d', time_rule='09:40:00')


def algo(context):
    # 获取上一个交易日的日期
    last_day = get_previous_trading_date(exchange='SHSE', date=context.now)
    #计算前一日的RSRS斜率
    prices = history_n(symbol='SHSE.000300', frequency='1d', count=context.N, end_time=last_day, fields='', skip_suspended=True,
                       fill_missing=None, adjust=ADJUST_PREV, adjust_end_time='', df=True)
    #做回归计算
    highs = prices.high
    lows = prices.low
    X = sm.add_constant(lows)
    model = sm.OLS(highs, X)
    results = model.fit().params[1]

    if results > context.buy:
        order_target_percent(symbol='SHSE.000300', percent=1, order_type=OrderType_Market,
                             position_side=PositionSide_Long)

    if results < context.sell:
        order_close_all()



if __name__ == '__main__':
    run(strategy_id='73bb5bf2-a536-11e8-bd52-9cd21ef04ea9',
        filename='789.py',
        mode=MODE_BACKTEST,
        token='c395247a76e8a5caeee699d668d6f550213bc418',
        backtest_start_time='2014-01-01 08:00:00',
        backtest_end_time='2018-01-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0,
        backtest_slippage_ratio=0)

7.有效因子 

# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
import multiprocessing
import numpy as np
import pandas as pd
from gm.api import *
import matplotlib.pyplot as plt

#本策略基于掘金量化交易平台 网址:www.myquant.cn

def init(context):
            # 每月第一个交易日09:40:00的定时执行algo任务
            schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')

def algo(context):
            # 获取当前时刻
            now = context.now
            # 获取上一个交易日
            last_day = get_previous_trading_date(exchange='SHSE', date=now)
            # 获取IT指数成份股
            stock300 = get_history_constituents(index='SZSE.399239', start_date=last_day,
                                                end_date=last_day)[0]['constituents'].keys()
            # 获取当天有交易的股票
            not_suspended_info = get_history_instruments(symbols=stock300, start_date=now, end_date=now)
            not_suspended_symbols = [item['symbol'] for item in not_suspended_info if not item['is_suspended']]
            fin = get_fundamentals(table='trading_derivative_indicator', symbols=not_suspended_symbols,
                                   start_date=now, end_date=now, fields='PELFYNPAAEI',
                                   filter='PELFYNPAAEI >0 or PELFYNPAAEI <0', order_by='PELFYNPAAEI', df=True)
            long=len(fin)
            if context.stockrange==0.1:
                stockpool = list(fin.symbol)[0:int(long * context.stockrange)-1]
            else:
                stockpool = list(fin.symbol)[int(long*(context.stockrange-0.1))-1:int(long*context.stockrange)-1]
            #清仓
            order_close_all()

            # 获取股票的权重
            percent = 1.0 / len(stockpool)
            # 买在标的池中的股票
            for symbol in stockpool:
                order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
                                     position_side=PositionSide_Long)

# 获取每次回测的报告数据
def on_backtest_finished(context, indicator):

    data = [indicator['pnl_ratio'],indicator['pnl_ratio']+0.189, indicator['pnl_ratio_annual'], indicator['sharp_ratio'], indicator['max_drawdown'],
            context.stockrange]
    # 将回测报告加入全局list,以便记录
    context.list.append(data)


def run_strategy(stockrange, a_list):
    from gm.model.storage import context
    # 用context传入参数
    context.stockrange = stockrange
    # a_list一定要传入
    context.list = a_list
    run(strategy_id='3e6dc538-947a-11e8-89c4-9cd21ef04ea9',
        filename='有效因子.py',
        mode=MODE_BACKTEST,
        token='c395247a76e8a5caeee699d668d6f550213bc418',
        backtest_start_time='2017-01-01 08:00:00',
        backtest_end_time='2018-01-01 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=50000,
        backtest_commission_ratio=0,
        backtest_slippage_ratio=0)


if __name__ == '__main__':
    # 生成全局list
    manager = multiprocessing.Manager()
    a_list = manager.list()
    # 循环输入参数数值回测
    for stockrange in np.arange(0.1, 1.1, 0.1):
            print(stockrange)
            process = multiprocessing.Process(target=run_strategy, args=(stockrange, a_list))
            process.start()
            process.join()
    # 回测报告转化成DataFrame格式
    a_list = np.array(a_list)
    final = pd.DataFrame(a_list,columns=['pnl_ratio', 'Alpha','pnl_ratio_annual', 'sharp_ratio', 'max_drawdown', 'stockrange'])
    fig = plt.figure(figsize=(12, 6))
    fig.set_facecolor('white')
    plt.bar(final.loc[final.Alpha>0].index, final.loc[final.Alpha>0].Alpha, align='center',color='r', width=0.3)
    plt.bar(final.loc[final.Alpha < 0].index, final.loc[final.Alpha < 0].Alpha, align='center',color='g', width=0.3)
    plt.title('PELFYNPAAEI')
    plt.show()
    print(final)

8.冗余因子去除

from __future__ import print_function, absolute_import, unicode_literals
import seaborn as sns
import pandas as pd
from gm.api import *
import matplotlib.pyplot as plt
set_token('c395247a76e8a5caeee699d668d6f550213bc418')

#本策略基于掘金量化交易平台 网址:www.myquant.cn

#相关性矩阵热力图
def cor(df):
    dfData = df.corr()
    plt.subplots(figsize=(9, 9)) # 设置画面大小
    sns.heatmap(dfData, annot=True, vmax=1, square=True, cmap="Blues")
    plt.savefig('./BluesStateRelation.png')
    plt.show()

#获取每月第一个交易日
time=get_trading_dates(exchange='SHSE', start_date='2016-01-01', end_date='2018-01-01')
date=[]
for i in time:
    n=time.index(i)
    if i[5:7]!=time[n-1][5:7]:
        date.append(i)

#测试因子间相关性
for tradedate in date:
    data=pd.DataFrame()
    fin=pd.DataFrame()
    a=0
    for factor in ['PB','ROEANNUAL','TAGRT','SHTLIABTOTLIABRT']:
            n=date.index(tradedate)
            if n ==23:
                break
            # 获取上一个交易日
            last_day = get_previous_trading_date(exchange='SHSE', date=tradedate)
            nextmoth=date[n+1]
            # 获取上证50成份股
            stock300 = get_history_constituents(index='SHSE.000016', start_date=last_day,
                                                end_date=last_day)[0]['constituents'].keys()
            # 获取当天有交易的股票
            not_suspended_info = get_history_instruments(symbols=stock300, start_date=tradedate, end_date=tradedate)
            not_suspended_symbols = [item['symbol'] for item in not_suspended_info if not item['is_suspended']]
            #获取因子数据
            if factor=='PB':
                fin = get_fundamentals(table='trading_derivative_indicator', symbols=not_suspended_symbols,
                                       start_date=tradedate, end_date=tradedate, fields=factor,
                                       filter='', order_by='-' + factor, df=True)
            else:
                fin = get_fundamentals(table='deriv_finance_indicator', symbols=not_suspended_symbols,
                                   start_date=tradedate, end_date=tradedate, fields=factor,
                                   filter='', order_by='-'+factor, df=True)
            long=len(fin)
            fin=fin.fillna(0)
            portfolio=[]

            #获取股票收益率
            for i in fin.symbol:
                try :
                    last=history(symbol=i, frequency='1d', start_time=nextmoth, end_time=nextmoth, fields='close', skip_suspended=True,
                    fill_missing=None, adjust=ADJUST_NONE, adjust_end_time='', df=False)[0]['close']
                except:
                    portfolio.append(0)
                    continue
                pre=history(symbol=i, frequency='1d', start_time=tradedate, end_time=tradedate, fields='close', skip_suspended=True,
                    fill_missing=None, adjust=ADJUST_NONE, adjust_end_time='', df=False)[0]['close']
                portfolio.append((last - pre) / pre)
            #根据收益率对股票进行打分
            portfolio_2=[(sum(portfolio[0:4]))/5]*5+[(sum(portfolio[5:9]))/5]*5+[(sum(portfolio[10:14]))/5]*5+[(sum(portfolio[15:19]))/5]*5+[(sum(portfolio[20:24]))/5]*5+[(sum(portfolio[25:29]))/5]*5+[(sum(portfolio[30:34]))/5]*5+[(sum(portfolio[35:39]))/5]*5+[(sum(portfolio[40:44]))/5]*5+[(sum(portfolio[45-long:0]))/5]*(long-45)
            fin['portfolio_2'] = portfolio_2
            fin=fin.sort_values(by = 'portfolio_2',axis = 0,ascending = False)
            score=[10]*5+[9]*5+[8]*5+[7]*5+[6]*5+[5]*5+[4]*5+[3]*5+[2]*5+[1]*(long-45)
            fin[factor + 'score'] =score
            del fin['pub_date'],fin['end_date'],fin['portfolio_2'],fin[factor]
            a=a+1
            #获取关于四个因子下,每个股票所获得的分数值
            if a==1:
                data=fin
            else:
                data = pd.merge(data, fin, how='right', on='symbol')
    #统计分析
    del data['symbol']
    cor(data)
    print(data.corr())
发布了1 篇原创文章 · 获赞 6 · 访问量 4944

猜你喜欢

转载自blog.csdn.net/zk168_net/article/details/104647183
今日推荐