加载中…

加载中...

个人资料
faruto
faruto 新浪个人认证
  • 博客等级:
  • 博客积分:0
  • 博客访问:1,144,854
  • 关注人气:2,115
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
正文 字体大小:

一种简化的截面动量组合测试[Python&MATLAB]

(2015-03-09 23:32:04)
标签:

matlab

python

quant

量化投资

股票

分类: MATLAB量化投资策略分析

下面的例子来源书籍


策略比较简单,使用N只股票构建投资组合,计算每只股票的过去LookBack(参数)日的动量,并作标准化处理作为股票权重,持有Holding(参数)日,其中权重允许为负数,即允许做空股票。简要说来就是做过过去表现强势的股票,做空过去表现弱势的股票。


虽然策略比较简单,但整体的测试流程和框架很明了清晰,对类似策略的回测实现具有参考意义,整体的流程框架为:


数据获取(基于付费或者免费的数据源)——

数据的时间轴对齐以及缺失数据填充——

子函数编写:特定回顾期的动量计算并作标准化——

子函数编写:给定回顾期和持有期,组合的夏普比例计算——

计算不同回顾期和持有期下组合的夏普比例值——

进行策略参数分布图形展示


一、Python下的实现测试。


1)主要用到numpypandasmatplotlib等几个包


# -*- coding: utf-8 -*-
"""
SimpleMomentumPortfolioTest 
Created on 2015/05/01
@author: LiYang(faruto)
@group : FQuantStudio
@contact: farutoliyang@foxmail.com
"""

#%% import
import numpy as np
import pandas as pd
import pandas.io.data as web
import matplotlib.pylab as plt

from pandas import Series,DataFrame
from collections import defaultdict


2)数据的获取基于pandas


#%% GetData

names = ['AAPL', 'GOOGL', 'MSFT', 'IBM', 'GS', 'MS', 'BAC', 'C']


def get_px(stock, start, end):
    return web.get_data_yahoo(stock, start, end)['Adj Close']
    
px = DataFrame({n: get_px(n, '1/1/2005', '1/1/2015') for n in names})

px.plot()



3)数据的时间轴对齐以及缺失数据填充


#%% plot

px = px.asfreq('B').fillna(method='pad')
rets = px.pct_change()

retcum = (1+rets).cumprod()-1
retcum.plot()

一种简化的截面动量组合测试[Python&MATLAB]


4)子函数编写:特定回顾期的动量计算并作标准化


#%% calc_mom

def calc_mom(price, lookback, lag):
    mom_ret = price.shift(lag).pct_change(lookback)
    ranks = mom_ret.rank(axis=1, ascending=False)
    demeaned = ranks.subtract(ranks.mean(axis=1), axis=0)
    return demeaned.divide(demeaned.std(axis=1), axis=0)

当然这里是做了排序后把排序变量做标准化后返回。


5)子函数编写:给定回顾期和持有期,组合的夏普比例计算


#%% strat_sr

compound = lambda x : (1 + x).prod() - 1
daily_sr = lambda x: x.mean() / x.std()

def strat_sr(prices, lb, hold):
    # Compute portfolio weights
    freq = '�' % hold
    port = calc_mom(prices, lb, lag=1)

    daily_rets = prices.pct_change()

    # Compute portfolio returns
    port = port.shift(1).resample(freq, how='first')
    returns = daily_rets.resample(freq, how=compound)
    port_rets = (port * returns).sum(axis=1)

    return daily_sr(port_rets) * np.sqrt(252 / hold)


strat_sr(px, 70, 30)

6)计算不同回顾期和持有期下组合的夏普比例值


#%% calc with diff lookbacks and holdings

lookbacks = range(20, 90, 5)
holdings = range(20, 90, 5)
dd = defaultdict(dict)
for lb in lookbacks:
    for hold in holdings:
        dd[lb][hold] = strat_sr(px, lb, hold)

ddf = DataFrame(dd)
ddf.index.name = 'Holding Period'
ddf.columns.name = 'Lookback Period'

7)进行策略参数分布图形展示


#%% heatmap

def heatmap(df, cmap=plt.cm.gray_r):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    axim = ax.imshow(df.values, cmap=cmap, interpolation='nearest')
    ax.set_xlabel(df.columns.name)
    ax.set_xticks(np.arange(len(df.columns)))
    ax.set_xticklabels(list(df.columns))
    ax.set_ylabel(df.index.name)
    ax.set_yticks(np.arange(len(df.index)))
    ax.set_yticklabels(list(df.index))
    plt.colorbar(axim)

heatmap(ddf)


一种简化的截面动量组合测试[Python&MATLAB]

通过上图可以看到在此例下,大概回顾期为55-60日,持有期为35-40日,会获取较高的夏普比率。


总结:可以看到在Python下使用pandas包整体的实现测试过程很简单明了。Pandas是个进行数据分析处理很赞的包。



二、MATLAB下的实现测试。


下面在来看下在MATLAB下的实现测试过程,不同的语言各有利弊,并无本质上哪个好,那个坏之说,本例中,由于Python下的pandas包的帮助,在Python下的代码更加简洁明了,MATLAB下代码稍显臃肿,当然也可以仿照Python下的pandas包,实现一个MATLAB下的pandas包,让相关的数据处理更加简洁方便。虽然MATLAB下的金融工具箱有fintsfinancial time series类)、timeseries类,但相关的实现和处理在效率和使用上并不是特别好,所以时序相关的处理我还是自己实现的,并没有全部使用MATLAB自带的一些包。

注:MATLAB的实现测试使用的A股的数据,数据的获取基于FQuantToolBox


1)函数说明


function SimpleMomentumPortfolioTest
% by LiYang_faruto
% Email:farutoliyang@foxmail.com
% 2015/01/01
%% A Little Clean Work
% clear;
% clc;
% close all;
format compact;

2)数据的获取基于FQuantToolBox


%% GetDataFromWeb
tic;
StockCodeCell = {'600588sh','sh600030','600446','300024sz','sz000001','600570sh'};
StockNameCell = {'用友网络','中信证券','金证股份','机器人','平安银行','恒生电子'};

BeginDate = '20100101';
EndDate = '20150101';
Len = length(StockCodeCell);
StockDataCell = cell(length(StockCodeCell),1);
for i = 1:length(StockCodeCell)
     StockCode = StockCodeCell{i};
     [StockDataCell{i}] = GetStockTSDay_Web(StockCode,BeginDate,EndDate);
end

toc;
%% 前复权数据生成
StockDataCellXRD = StockDataCell;
for i = 1:Len
    StockData = StockDataCell{i};
    AdjFlag = 1;
    [StockDataCell{i}] = CalculateStockXRD(StockData, [], AdjFlag);
end


3)数据的时间轴对齐以及缺失数据填充


tic;
sdate = datenum(BeginDate,'yyyymmdd');
edate = datenum(EndDate,'yyyymmdd');
bdates = busdays(sdate, edate, 'Daily');
Bdates = str2num( datestr(bdates,'yyyymmdd') );

StockDataCell_pre = StockDataCell;
for i = 1:Len
    tMat = zeros(length(Bdates),8);
    tMat(:,1) = Bdates;
    
    tMat_pre = StockDataCell{i};
    for j = 1:length(Bdates)
        tD = Bdates(j);
        ind = find(tMat_pre(:,1)<=tD, 1,'last');
        tMat(j,2:end) = tMat_pre(ind,2:end);
    end
    
    StockDataCell{i} = tMat;
end
toc;
%% 每只股票累计收益
StockMat = zeros(length(Bdates), Len+1);
StockMat(:,1) = Bdates;
for i = 1:Len
    StockMat(:,i+1) = StockDataCell{i}(:,5);
end

Ret = tick2ret(StockMat(:,2:end));
CumRet = cumprod((1+Ret))-1;

scrsz = get(0,'ScreenSize');
figure('Position',[scrsz(3)*1/4 scrsz(4)*1/6 scrsz(3)*4/5 scrsz(4)]*3/4);
plot(CumRet,'LineWidth',1.5);
xlim([0,length(Bdates)+1]);
Dates = StockMat(2:end,1);
LabelSet(gca, Dates, [], [], 1);

M = StockNameCell;
H = legend(M);
H.Orientation = 'horizontal';
H.FontWeight = 'Bold';
H.FontSize = 12;
H.Location = 'northoutside';

str = '股票累计收益';
H = title(str);
H.FontWeight = 'Bold';
H.FontSize = 15;

一种简化的截面动量组合测试[Python&MATLAB]

4)子函数编写:特定回顾期的动量计算并作标准化


%% sub fun calc_mom 
% ---------------------------------------------------
%  calc_mom
% ---------------------------------------------------
function weight = calc_mom(price,lookback)
    weight = zeros(size(price));
    weight(:,1) = price(:,1);
    [m,n] = size(price);
    % weight(1:lookback,2:end) = nan;
    weight(1:lookback,2:end) = 0;
    for j = lookback+1:m 
        for i = 2:n
            tData = price(:,i);
            weight(j,i) =  (tData(j-1)-tData(j-lookback))/tData(j-lookback);
        end
        
        temp = weight(j,2:end);
        weight(j,2:end) = (temp-mean(temp))./std(temp);
    end
    
    weight(isnan(weight)) = 0;
end    

当然这里与Python下稍有不同,就使用标准化后的动量值返回。


5)子函数编写:给定回顾期和持有期,组合的夏普比例计算


%% sub fun strat_sr
% ---------------------------------------------------
%  strat_sr
% ---------------------------------------------------
function SR = strat_sr(prices, lb, hold)
    SR = 0;
    [m,n] = size(prices);
    % 计算权重
    port = calc_mom(prices,lb);
    port(isnan(port)) = 0;
    
    % 计算组合收益
    PortResample = [];
    Returns = [];
    Ind = 1;
    for i = hold:hold:m
        PortResample(Ind,:) = port(i-hold+1,:);
        Returns(Ind,:) = prices(i,:);
        Returns(Ind,2:end) = (prices(i,2:end)-prices(i-hold+1,2:end))./prices(i-hold+1,2:end);

        Ind = Ind + 1;
    end
    port_rets = PortResample(:,2:end).*Returns(:,2:end);
    port_rets = sum(port_rets,2);
    % 计算年化Sharpe Ratio
    SR = mean(port_rets)/std(port_rets)*sqrt( 252/hold );

end

6)计算不同回顾期和持有期下组合的夏普比例值


%% calc
tic;
lookbacks = 20:5:90;
holdings = 20:5:100;

DD = zeros(length(lookbacks), length(holdings));

for i = 1:length(lookbacks)
    for j = 1:length(holdings)
        lb = lookbacks(i);
        hold = holdings(j);
        DD(i,j) = strat_sr(StockMat, lb, hold);
    end
end
toc;

7)进行策略参数分布图形展示


%% HeatPlot
temp = num2cell(lookbacks);
temp = cellfun(@num2str,temp,'UniformOutput',false);
YVarNames = temp;

temp = num2cell(holdings);
temp = cellfun(@num2str,temp,'UniformOutput',false);
XVarNames = temp;

XLabelString = 'Holding Period';
YLabelString = 'Lookack Period';
Fmatrixplot(DD,'ColorBar','On','XVarNames',XVarNames,'YVarNames',YVarNames,...
    'XLabelString',XLabelString,'YLabelString',YLabelString);

一种简化的截面动量组合测试[Python&MATLAB]

通过上图可以看到在此例下,大概回顾期为25-35日,持有期为60日,会获取较高的夏普比率。



总结

本文给出了一个简化的截面动量组合测试,虽然策略比较简单,但整体的测试流程和框架很明了清晰,对类似策略的回测实现具有参考意义,整体的流程框架为:

 

数据获取(基于付费或者免费的数据源)——》

数据的时间轴对齐以及缺失数据填充——》

子函数编写:特定回顾期的动量计算并作标准化——》

子函数编写:给定回顾期和持有期,组合的夏普比例计算——》

计算不同回顾期和持有期下组合的夏普比例值——》

进行策略参数分布图形展示


Pythonpandas是个数据处理非常不错的一个包,另外在Python下免费的A股数据可以通过tushare 包(作者Jimmy)获取,tushare 包下载地址:http://tushare.waditu.com/

MATLAB下,虽然此例的实现测试稍显臃肿,但也不是非常复杂。在MATLAB下免费的A股数据可以通过FQuantToolBox(作者faruto)获取,FQuantToolBox下载地址:

一种简化的截面动量组合测试[Python&MATLAB]


欢迎关注微信公众号 FQuantStudio

一种简化的截面动量组合测试[Python&MATLAB]

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有