pythonplot绘图xrd_一种简化的截面动量组合测试[PythonMATLAB]
下面的例子來源書籍
策略比較簡單,使用N只股票構建投資組合,計算每只股票的過去LookBack(參數)日的動量,并作標準化處理作為股票權重,持有Holding(參數)日,其中權重允許為負數,即允許做空股票。簡要說來就是做過過去表現強勢的股票,做空過去表現弱勢的股票。
雖然策略比較簡單,但整體的測試流程和框架很明了清晰,對類似策略的回測實現具有參考意義,整體的流程框架為:
數據獲取(基于付費或者免費的數據源)——》
數據的時間軸對齊以及缺失數據填充——》
子函數編寫:特定回顧期的動量計算并作標準化——》
子函數編寫:給定回顧期和持有期,組合的夏普比例計算——》
計算不同回顧期和持有期下組合的夏普比例值——》
進行策略參數分布圖形展示
一、Python下的實現測試。
(1)主要用到numpy、pandas、matplotlib等幾個包
# -*- 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()
(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 = '%dB' % 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)
通過上圖可以看到在此例下,大概回顧期為55-60日,持有期為35-40日,會獲取較高的夏普比率。
總結:可以看到在Python下使用pandas包整體的實現測試過程很簡單明了。Pandas是個進行數據分析處理很贊的包。
二、MATLAB下的實現測試。
下面在來看下在MATLAB下的實現測試過程,不同的語言各有利弊,并無本質上哪個好,那個壞之說,本例中,由于Python下的pandas包的幫助,在Python下的代碼更加簡潔明了,MATLAB下代碼稍顯臃腫,當然也可以仿照Python下的pandas包,實現一個MATLAB下的pandas包,讓相關的數據處理更加簡潔方便。雖然MATLAB下的金融工具箱有fints(financial 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;
(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);
通過上圖可以看到在此例下,大概回顧期為25-35日,持有期為60日,會獲取較高的夏普比率。
總結
本文給出了一個簡化的截面動量組合測試,雖然策略比較簡單,但整體的測試流程和框架很明了清晰,對類似策略的回測實現具有參考意義,整體的流程框架為:
數據獲取(基于付費或者免費的數據源)——》
數據的時間軸對齊以及缺失數據填充——》
子函數編寫:特定回顧期的動量計算并作標準化——》
子函數編寫:給定回顧期和持有期,組合的夏普比例計算——》
計算不同回顧期和持有期下組合的夏普比例值——》
進行策略參數分布圖形展示
在Python下pandas是個數據處理非常不錯的一個包,另外在Python下免費的A股數據可以通過tushare 包(作者Jimmy)獲取,tushare 包下載地址:TuShare -財經數據接口包。
在MATLAB下,雖然此例的實現測試稍顯臃腫,但也不是非常復雜。在MATLAB下免費的A股數據可以通過FQuantToolBox(作者faruto)獲取,FQuantToolBox下載地址:FQuantToolBoxHelpOnLine
總結
以上是生活随笔為你收集整理的pythonplot绘图xrd_一种简化的截面动量组合测试[PythonMATLAB]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql 事务autocommit_亲
- 下一篇: 性能测试在软件测试中的位置,性能测试的响