python BACKTEST MULTI-STRATEGY(INCL DUAL MUMENTUM)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python BACKTEST MULTI-STRATEGY(INCL DUAL MUMENTUM)相关的知识,希望对你有一定的参考价值。

import pandas_datareader.data as web
import matplotlib.pyplot as plt
import pandas as pd
from datetime import datetime, timezone
import itable
import ffn
import pytz

from fintools import get_DataArray,show_return_table, show_annual_returns, monthly_return_table
from fintools import Parameters,compute_weights_RS_DM,compute_weights_PMA, generate_orders
from fintools import endpoints, backtest

# %matplotlib inline

start = datetime(2000, 1, 1, 0, 0, 0, 0, pytz.utc)
end = datetime.today().replace(tzinfo=timezone.utc)

# CHOOSE EITHER ETFs OR FUNDS

# ETFs

# strategies = {
#     'RS0001': { 'assets': ['CWB','HYG','MBB','IEF','HYD'],
#                'start':start, 'end':end,
#                'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 2, 'frequency': 'M',
#               'cash_proxy': 'CASHX', 'risk_free': 0},
#     'RS0002': {'assets': ['HYD','QLTB','MBB'],
#                'start':start, 'end':end,
#                'rs_lookback': 3, 'risk_lookback': 2, 'n_top': 1, 'frequency': 'M',
#               'cash_proxy': 'CASHX', 'risk_free': 0},
#     'RS0003': {'assets': ['HYD','MBB','SHY'],
#                'start':start, 'end':end,
#                'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 1, 'frequency': 'Q',
#               'cash_proxy': 'CASHX', 'risk_free': 0},
#     'DM0001': {'assets': ['CWB','VYM','HYG','VHT','TLT','MBB','HYD','IEF'],
#                'start':start, 'end':end,
#                'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 3, 'frequency': 'M',
#               'cash_proxy': 'CASHX', 'risk_free': 'SHY'},
#     'DM0002': {'assets': ['CWB','TLT','HYG','VHT','VNQ'],
#                'start':start, 'end':end,
#                'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 5, 'frequency': 'M',
#               'cash_proxy': 'MBB', 'risk_free': 'SHY'},
#     'PMA001': {'assets': ['CWB','MBB'],
#                'start':start, 'end':end,
#                'risk_lookback': 3, 'frequency': 'M', 'allocations': [0.6, 0.4],
#               'cash_proxy': 'TLT'},
#     'PMA002': {'assets': ['CWB','VYM','HYG'],
#                'start':start, 'end':end,
#                'risk_lookback': 3, 'frequency': 'M', 'allocations': [0.6, 0.2, 0.2],
#               'cash_proxy': 'TLT'},
#     'PMA003': {'assets': ['VCVSX', 'FAGIX', 'VGHCX'],
#                'start':start, 'end':end,
#                'risk_lookback': 2, 'frequency': 'M', 'allocations': [1./3., 1./3., 1./3.],
#               'cash_proxy': 'VUSTX'}
#     }

# FUNDS

strategies = {
    'RS0001': { 'assets': ['VCVSX','VWEHX','VFIIX','FGOVX','VWAHX'],
               'start':start, 'end':end,
               'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 2, 'frequency': 'M',
              'cash_proxy': 'CASHX', 'risk_free': 0},
    'RS0002': {'assets': ['MMHYX','FAGIX','VFIIX'],
               'start':start, 'end':end,
               'rs_lookback': 3, 'risk_lookback': 2, 'n_top': 1, 'frequency': 'M',
              'cash_proxy': 'CASHX', 'risk_free': 0},
    'RS0003': {'assets': ['MMHYX','FAGIX','VFIIX'],
               'start':start, 'end':end,
               'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 1, 'frequency': 'Q',
              'cash_proxy': 'CASHX', 'risk_free': 0},
    'DM0001': {'assets': ['VCVSX','VWINX','VWEHX','VGHCX','VUSTX','VFIIX','VWAHX','FGOVX','FFXSX'],
               'start':start, 'end':end,
               'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 3, 'frequency': 'M',
              'cash_proxy': 'CASHX', 'risk_free': 'FFXSX'},
    'DM0002': {'assets': ['VCVSX','VUSTX','VWEHX','VFIIX','VGHCX','FRESX'],
               'start':start, 'end':end,
               'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 5, 'frequency': 'M',
              'cash_proxy': 'VFIIX', 'risk_free': 'FFXSX'},
    'PMA001': {'assets': ['VCVSX', 'VFIIX'],
               'start':start, 'end':end,
               'risk_lookback': 3, 'frequency': 'M', 'allocations': [0.6, 0.4],
              'cash_proxy': 'VUSTX'},
    'PMA002': {'assets': ['VCVSX', 'VWINX', 'VWEHX'],
               'start':start, 'end':end,
               'risk_lookback': 3, 'frequency': 'M', 'allocations': [0.6, 0.2, 0.2],
              'cash_proxy': 'VUSTX'},
    'PMA003': {'assets': ['VCVSX', 'FAGIX', 'VGHCX'],
               'start':start, 'end':end,
               'risk_lookback': 2, 'frequency': 'M', 'allocations': [1./3., 1./3., 1./3.],
              'cash_proxy': 'VUSTX'}
    }

strategy_values = {}
security_weights = {}
security_holdings = {}
prices = {}

for name in strategies:
    if 'PMA' in name:
        try:
            s_value, s_holdings, s_weights, s_prices = compute_weights_PMA(name, strategies[name])
        except:
            print('*** Unable to use PMA strategy : ' + name)
            name = 'None'
    else:
        try:
            s_value, s_holdings, s_weights, s_prices = compute_weights_RS_DM(name, strategies[name])
        except:
            print('*** Unable to use RS_DM strategy : ' + name)
            name = 'None'

    if name != 'None':
        strategy_values[name] = s_value
        security_weights[name] = s_weights
        security_holdings[name] = s_holdings
        prices[name] = s_prices

columns = list(strategy_values.keys())
# strategy_values[columns].plot(figsize=(15,10), grid=True, legend=True)

strategy_values = pd.DataFrame(strategy_values).dropna()
index = strategy_values.index
rebalance_dates = endpoints(period='M', trading_days=index)

# find the set of all portfolio symbols
n = len(columns)
l = [list(security_weights[name].columns) for name in columns]
s = []
for i in range(n):
    s = s + l[i]

aggregated_weights = pd.DataFrame(0, index=rebalance_dates, columns=list(set(s)))
all_prices = pd.DataFrame(0, index=index, columns=list(set(s)))

# for equally weighted strategies
strategy_weights = pd.Series([1. / n for i in range(n)], index=columns)
for name in columns :
    aggregated_weights[security_weights[name].columns] += security_weights[name].loc[rebalance_dates] * strategy_weights[name]
    all_prices = prices[name].loc[index].combine_first(all_prices)

p_value, p_holdings, p_weights = backtest(all_prices, aggregated_weights, 10000., offset=0, commission=10.)

# p_value.plot(figsize=(15,10), grid=True, legend=True)

# algo stats
ffn.calc_perf_stats(p_value).display()

show_return_table(p_value)

show_annual_returns(p_value)

# HOLDINGS, TRANSACTIONS AND ORDERS
holdings = p_holdings.loc[rebalance_dates].round(0)
transactions = (p_holdings - p_holdings.shift(1).fillna(0))
transactions = transactions[transactions.sum(1) != 0].round(0)
orders = generate_orders(transactions, all_prices)
##################################################
# DUAL MOMENTUM
###############

strategy_prices = strategy_values.dropna().copy()
# need to add prices for cash_proxy and, if necessary, risk_free

d = get_DataArray(['FFXSX'],start,end).to_pandas().transpose(1,2,0)
strategy_prices['FFXSX'] = d[:,:,'adj close'].loc[s_prices.index]

strategies1 = {
    'MUTLTI-RS': { 'assets': list(strategies.keys()), 'prices': strategy_prices,
               'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 8, 'frequency': 'm',
              'cash_proxy': 'FFXSX', 'risk_free': 0}}

for name in strategies1 :
    s_value, s_holdings, s_weights, s_prices =  compute_weights_RS_DM (name, strategies1[name])

# poorer return but lower drawdown and better SR
ffn.calc_perf_stats(s_value).display()
########################################################################################################
# This to calculate the orders at each rebalance date
#####################################################◙

# get weights from backtest
strategy_weights = s_weights.loc[rebalance_dates].copy()
aggregated_weights = pd.DataFrame(0, index=rebalance_dates, columns=list(set(s + ['FFXSX'])))
all_prices = pd.DataFrame(0, index=index, columns=list(set(s + ['FFXSX'])))

prices = security_prices.copy()
for name in strategies:
    aggregated_weights[security_weights[name].columns] += security_weights[name].loc[rebalance_dates].mul(
        strategy_weights[name], axis=0)
    all_prices = prices[name].loc[index].combine_first(all_prices)

# need to add in the cash_proxy weights
aggregated_weights['FFXSX'] = aggregated_weights['FFXSX'].add(strategy_weights['FFXSX'], axis=0)

aggregated_weights = aggregated_weights[aggregated_weights.sum(1) > 0]
values, holdings, weights = backtest(all_prices, aggregated_weights, 10000., offset=0, commission=10.)

transactions = (holdings - holdings.shift(1).fillna(0))
transactions = transactions[transactions.sum(1) != 0]
orders = generate_orders(transactions, all_prices)

以上是关于python BACKTEST MULTI-STRATEGY(INCL DUAL MUMENTUM)的主要内容,如果未能解决你的问题,请参考以下文章

python BACKTEST RS_DM或PMA STEP_BY_STEP

合并两个数据帧r进行回测

fetch_csv使用

fetch_csv使用

fetch_csv使用

代写python,代写python编程,python代写,python编程代写,留学生python代写