克隆策略
In [ ]:
import numpy as np
import matplotlib.pyplot as plt
import cvxopt as opt
from cvxopt import blas, solvers
import pandas as pd
In [99]:
def optimal_portfolio(returns):
    n = len(returns)
    returns = np.asmatrix(returns)
    
    N = 100
    mus = [10**(5.0 * t/N - 1.0) for t in range(N)]
    
    # 转化为cvxopt matrices
    S = opt.matrix(np.cov(returns))
    pbar = opt.matrix(np.mean(returns, axis=1))
    
    # 约束条件
    G = -opt.matrix(np.eye(n))   # opt默认是求最大值,因此要求最小化问题,还得乘以一个负号
    h = opt.matrix(0.0, (n ,1))
    A = opt.matrix(1.0, (1, n))
    b = opt.matrix(1.0)
    
    # 使用凸优化计算有效前沿
    portfolios = [solvers.qp(mu*S, -pbar, G, h, A, b)['x'] 
                  for mu in mus]
    ## 计算有效前沿的收益率和风险
    returns = [blas.dot(pbar, x) for x in portfolios]
    risks = [np.sqrt(blas.dot(x, S*x)) for x in portfolios]
    m1 = np.polyfit(returns, risks, 2)
    x1 = np.sqrt(m1[2] / m1[0])
    # 计算最优组合
    wt = solvers.qp(opt.matrix(x1 * S), -pbar, G, h, A, b)['x']
    return np.asarray(wt), returns, risks

#weights, returns, risks = optimal_portfolio(return_vec)
In [100]:
# 获取数据
start_date = '2017-02-01'
end_date = '2017-12-10'
instruments = ['600000.SHA','600016.SHA','600019.SHA','600028.SHA','600029.SHA','600030.SHA','600036.SHA','600048.SHA','600050.SHA','600104.SHA',
               '600111.SHA','600309.SHA','600340.SHA','600518.SHA','600519.SHA','600547.SHA','600606.SHA','600837.SHA','600887.SHA','600919.SHA',
               '600958.SHA','600999.SHA','601006.SHA','601088.SHA','601166.SHA','601169.SHA','601186.SHA','601211.SHA','601229.SHA','601288.SHA',
               '601318.SHA','601328.SHA','601336.SHA','601390.SHA','601398.SHA','601601.SHA','601628.SHA','601668.SHA','601669.SHA','601688.SHA',
               '601766.SHA','601800.SHA','601818.SHA','601857.SHA','601878.SHA','601881.SHA','601985.SHA','601988.SHA','601989.SHA','603993.SHA']
   
data = D.history_data(instruments,start_date,end_date,
                     fields=['close'])
# 整理数据
data = pd.pivot_table(data,values='close',index=['date'],columns=['instrument'])
#T.plot(data)
In [101]:
def initialize(context):
    
    context.days = 0
    context.ins = instruments
     
def handle_data(context, data):
    
    context.days += 1
    if context.days < 40:
        return
    # 每60天调仓一次
    if context.days % 30 != 0:
        return
    # 获取数据的时间窗口并计算收益率
    prices = data.history(context.symbols(context.ins[0],context.ins[1],context.ins[2],context.ins[3],context.ins[4]), 'price',40, '1d').dropna()
    returns = prices.pct_change().dropna()
    try:
        # 马科维茨组合优化
        weights, _, _ = optimal_portfolio(returns.T)
        print(weights)
        # 对持仓进行权重调整
        for stock, weight in zip(prices.columns, weights):
            if data.can_trade(stock):
                order_target_percent(stock, weight[0])
    except ValueError as e:
        pass
In [102]:
m = M.trade.v2(
    instruments=instruments,
    start_date=start_date,
    end_date=end_date,
    initialize=initialize,
    handle_data=handle_data,
    # 买入订单以开盘价成交
    order_price_field_buy='open',
    # 卖出订单以开盘价成交
    order_price_field_sell='open',
    capital_base=1000000,
    benchmark='000016.SHA',
)
[2018-01-13 18:11:17.503232] INFO: bigquant: backtest.v7 开始运行..
[2018-01-13 18:11:17.508873] INFO: bigquant: 命中缓存
  • 收益率40.82%
  • 年化收益率50.5%
  • 基准收益率18.16%
  • 阿尔法0.31
  • 贝塔0.83
  • 夏普比率1.59
  • 胜率0.455
  • 盈亏比1.196
  • 收益波动率28.91%
  • 信息比率1.03
  • 最大回撤17.48%
[2018-01-13 18:11:18.287655] INFO: bigquant: backtest.v7 运行完成[0.784391s].