simulation 2


# -*- coding: utf-8 -*-
"""strat_sz100iw.py
一种趋势策略的尝试, 针对深证100指数周线数据
"""
import itertools
import os, pathlib, datetime; type(os); type(pathlib);type(datetime)
import pandas as pd; type(pd)
import numpy as np; type(np)
import matplotlib.pyplot as plt

from copy import deepcopy;type(deepcopy)
from collections import OrderedDict ; type(OrderedDict)

import toolkit.myDataIO as mdio
import util.ttr as ttr     

import strat_sz100iw_report as wr; type(wr)

import imp; type(imp)
#imp.reload(mdio)
#imp.reload(ttr)

global g
g=ttr.GlobalEnv()
g.params=OrderedDict(
        atr_n=14, delta=0.5, sig_filter_n=3, 
        start_year=None, 
        code='399330',
        maxloss_pct=0.12,
        with_plot=False,
        )
#%%

#def simulation_LineMode(atr_n, delta, sig_filter_n, start_year=None, code='399330'):
def simulation_LineMode(**kwargs):
    '''
    Python里的可变参数(*和**字头的参数):
    在函数应用中(被定义或者被调用), 
    有时候我们不确定调用的时候会传递多少个参数(不传参也可以)。
    此时,可用包裹(packing)位置参数/包裹型位置参数,或者包裹型关键字参数,
    来进行参数传递, 会显得非常方便灵活。
    
    关键字参数(双星号字头的参数)允许你传入0个或任意个含参数名的参数,
    这些关键字参数在函数内部会自动组装为一个dict.

    >>> df_line=simulation_LineMode(**g.params) 
    atr14_pct=ttr.atr(df_line,14)/df_line.close *100
    atr14_pct.quantile() # 4.85%
    atr14_pct.describe()
    
    count    716.000000
    mean       5.476807
    std        2.481463
    min        2.134225
    25%        3.923625
    50%        4.851406
    75%        6.285523
    max       15.688897
    
    所以: stoploss的选择: 应该 > mean (or 1/2 quantile)
    '''
    global g 
    # 解包裹, 获取本函数所需的每个参数
    atr_n       =kwargs['atr_n']
    delta       =kwargs['delta']
    sig_filter_n=kwargs['sig_filter_n']
    start_year  =kwargs['start_year']
    code        =kwargs['code']
    with_plot   =kwargs['with_plot']
    
    fname = 'd:/new_haitong/T0002/export/{}.txt'.format(code)
    
    with open(fname, encoding='gbk') as f:
        first_line_data=f.readline()    
        asset_name=first_line_data.strip()
        title_='标的资产的代码和名称是: {}'.format(asset_name)
        print(title_)
        print('+'*(len(title_) + ttr.cchar(title_)))
    g.title_info=OrderedDict(
            fname=fname,
            asset_name=asset_name,
            )
    
    ohlc_ = mdio.read_tdxExport_txtFile(fname)
    ohlc=ohlc_[0]
    ohlc=ohlc.iloc[:, 0:5]
    
    if start_year:
        ohlc = ohlc[start_year:]
    out, perf_dict = ttr.strat_sz100iw_lm(ohlc, atr_n, delta, sig_filter_n, start_year)

    if with_plot:
        fig, ax=plt.subplots(1,1)
        ohlc.close.plot(ax=ax)
        out.bprice.plot(ax=ax)
        out.sprice.plot(ax=ax)
        out.equity.plot()
    
    print('
End equity : {:12.2f}
'.format(out.equity[-1] ,))
    [print('{0:{2:}s} : {1:}'.format(k, v, (18-ttr.cchar(k)))) for k, v in perf_dict.items()]
    print()
    return out

#%%

def simu_with_stoploss(atr_n=14, delta=0.5, sig_filter_n=3, 
                       start_year=None, 
                       code='399330',
                       
                       signal_type=1, # exRemoved, 0=original
                       maxloss_pct=0.11, 
                       stoploss_mode=1, # (0, 1)分别表示当日尾盘止损, 次日尾盘止损
                       trx_timing='closing',  
                       with_plot=False,
                       ):   
    '''
    >>> reset -f
    
    >>> pos,cagr,mdd,sharpe = simu_with_stoploss(maxloss_pct=0.13, signal_type=1, stoploss_mode=1, with_plot=False, trx_timing='closing')  #### 不错的止损值
    >>> pos,cagr,mdd,sharpe = simu_with_stoploss(maxloss_pct=0.13, signal_type=0, stoploss_mode=1, with_plot=False, trx_timing='closing')  #### 不错的止损值
    
    >>> pos,cagr,mdd,sharpe = simu_with_stoploss(maxloss_pct=0.13, stoploss_mode=1, with_plot=False, trx_timing='opening')  #
    
    >>> pos,cagr,mdd,sharpe = simu_with_stoploss(maxloss_pct=0.13, stoploss_mode=0, with_plot=False, trx_timing='closing')  #
    >>> pos,cagr,mdd,sharpe = simu_with_stoploss(maxloss_pct=0.13, stoploss_mode=0, with_plot=False, trx_timing='opening')  #
  
    >>> pos,cagr,mdd,sharpe = simu_with_stoploss(maxloss_pct=0.11, stoploss_mode=0, with_plot=True)  #### 不错的止损值
    >>> pos,cagr,mdd,sharpe=simu_with_stoploss(maxloss_pct=0.12, trx_timing='opening')  #### 不错的止损值
    

参数: OrderedDict(
[('atr_n', 14), ('delta', 0.5), ('sig_filter_n', 3), ('start_year', None), ('code', '399330'), 
('maxloss_pct', 0.12), ('trx_timing', 'closing'), ('with_plot', False)])

    下单指令集合: {'满仓寻出', '止损', '开仓', '空仓寻进', '清仓'}

dk          的次数:     49
dp          的次数:     45
gr          的次数:      4
hold_equity 的次数:    264
hold_cash   的次数:    326

end_equity        : 11541.354   if trx_timing=='opening'
end_nav           : 12.003      7.996
cagr              : 0.19        0.156
mdd               : 0.235       0.274
sharpe            : 1.151
annu_volatility   : 0.165
净值的标准差      : 0.023    
    '''
    global g
    #打包所需的关键字参数为: g.params, 方便调用函数时使用.
    g.params=OrderedDict(
            atr_n=atr_n, delta=delta, sig_filter_n=sig_filter_n, 
            start_year=start_year, 
            code=code,
            
            signal_type=signal_type,
            trx_timing=trx_timing, 
            maxloss_pct=maxloss_pct, 
            stoploss_mode=stoploss_mode, 
            
            with_plot=with_plot, 
            )
    
    df  = simulation_LineMode(**g.params)
    # print(df.columns)
    # Index(['open', 'high', 'low', 'close', 'trend', 
    # 'b_sig', 's_sig', 'bprice', 'sprice', 'buybars', 'sellbars', 
    # 'pos', 'equity', 'b22_sig', 's22_sig'],
    
    pos = ttr.simulation_BarMode(df, **g.params)
    pos = pos.set_index('dt', drop=False)
    
    print('
参数: {}'.format(g.params))
    ttr.print_orders_count(pos)
       
    pos_=pos.reindex(df.index)
    pos_.position.fillna(0.0, inplace=True)
    #print(set(pos_.position))
    roc1=df.close.pct_change().fillna(0)
    #交割时机的把握逻辑:
    #收盘时刻观察信号, 按收盘价成交:
    if trx_timing=='closing':
        eq = (1+roc1*pos_.position).cumprod() * df.close[0]
    elif trx_timing=='opening':
        # 校正持仓第一日的roc1: 应该为: 该日收盘价 to 该日开盘价
        #roc1_B = ttr.IF((df.b_sig.shift(1)>0, (df.open/df.close.shift(1)-1), roc1))
        roc1_B = ttr.IF((df.b_sig.shift(1)>0, (df.close/df.open-1), roc1))
        # 校正持仓最后日的roc1: 应该为: 次日开盘价 to 昨日收盘价
        # 下述方法仅保证了正常卖出时的收益率的正确性, 止损时的情形需要完善.
        #roc1_C = ttr.IF((df.s_sig>0,   (df.open.shift(-1)/df.close.shift(1)-1), roc1_B))
        exit_case = ttr.downCross(pos_.position, 0.5).shift(-1)
        roc1_C = ttr.IF(  (exit_case>0, 
                          (df.open.shift(-1)/df.close.shift(1)-1), 
                          roc1_B))
        eq = (1+roc1_C * pos_.position).cumprod() * df.close[0]
    pos_['open']=df.open
    pos_['close']=df.close
    pos_['equity']=eq
    

    perf_dict=ttr.perf(pos_)
    print()
    #[print('{:15s} : {}'.format(k, v)) for k, v in perf_dict.items()]
    for k, v in perf_dict.items():
        pwidth = 18 - ttr.cchar(k)
        print('{1:{0:}s} : {2:}'.format(pwidth, k, v)) 
    print()

    if with_plot:
        fig, ax=plt.subplots(1,1)
        pos_.close.plot(ax=ax)
        #out.bprice.plot(ax=ax)
        #out.sprice.plot(ax=ax)
        pos_.equity.plot()
    
    return pos_, perf_dict['cagr'], perf_dict['mdd'], perf_dict['sharpe']


#%%
def opt(trx_timing='closing', stoploss_mode=1, signal_type=1,):
    '''参数寻优
    最佳参数大概为: 
        14        atr_n, 
        13%       maxloss_pct, 
        'closing' trx_timing
        1         stoploss_mode (次日止损)
    绩效指标:
         CAGR   MDD     SHARPE
         19.5%  23.5%   1.180
         
         
    >>> opt_df=opt(trx_timing='closing', stoploss_mode=1, )
    >>> opt_df=opt(trx_timing='closing', stoploss_mode=1, signal_type=0) #用了原始信号后, 结果较差
    >>> opt_df=opt(trx_timing='opening', stoploss_mode=1)
    
    >>> opt_df=opt(trx_timing='closing', stoploss_mode=0, )
    >>> opt_df=opt(trx_timing='opening', stoploss_mode=0, signal_type=0) #更差

    stoploss_mode trx_timing  atr_n  maxloss_pct   cagr    mdd  sharpe
0               1    closing     13         0.05  0.173  0.359   1.107
1               1    closing     13         0.08  0.171  0.395   1.043
2               1    closing     13         0.11  0.181  0.395   1.098
3               1    closing     13         0.14  0.187  0.395   1.093
4               1    closing     14         0.05  0.160  0.248   1.058
5               1    closing     14         0.08  0.167  0.318   1.047
6               1    closing     14         0.11  0.184  0.235   1.142
7               1    closing     14         0.14  0.189  0.235   1.135

8               1    closing     15         0.05  0.152  0.391   0.987
9               1    closing     15         0.08  0.142  0.426   0.886
10              1    closing     15         0.11  0.150  0.445   0.923
11              1    closing     15         0.14  0.161  0.407   0.950


if 次日开盘成交: 那么结果如下: 
    成交时机选择当日尾盘略微好一点点(cagr能有3%的提升)
    但是没有明显的优势
    stoploss_mode trx_timing  atr_n  maxloss_pct   cagr    mdd  sharpe
0               1    opening     13         0.05  0.161  0.376   1.037
1               1    opening     13         0.08  0.165  0.376   1.010
2               1    opening     13         0.11  0.185  0.376   1.114
3               1    opening     13         0.14  0.176  0.392   1.022
4               1    opening     14         0.05  0.153  0.245   1.019
5               1    opening     14         0.08  0.160  0.310   1.013
6               1    opening     14         0.11  0.187  0.222   1.159

7               1    opening     14         0.14  0.180  0.222   1.076
8               1    opening     15         0.05  0.139  0.378   0.908
9               1    opening     15         0.08  0.134  0.378   0.842
10              1    opening     15         0.11  0.154  0.378   0.942
11              1    opening     15         0.14  0.151  0.383   0.879

    '''
    global g
    
    #把参数字典, 通过笛卡尔乘积, 转换为参数数据框
    par_dict = OrderedDict(
                    atr_n=range(13,16),
                    #maxloss_pct=np.arange(5,17,1)/100,
                    maxloss_pct=np.arange(5,17,1)/100,
                    )
    prod = itertools.product(*tuple(par_dict.values())) # 传递包裹型位置参数
    par_df = pd.DataFrame(list(prod), columns=par_dict.keys())

    out=pd.DataFrame()
    opt_summary=pd.DataFrame()
    for (i, atr_n, maxloss_pct ) in par_df.itertuples():
        pos, cagr, mdd, sharpe = simu_with_stoploss(
                atr_n=atr_n, 
                maxloss_pct=maxloss_pct, 
                signal_type=signal_type, 
                trx_timing=trx_timing, 
                stoploss_mode=stoploss_mode) 
        
        out['equity{}'.format(i)]=pos.equity
        opt_summary = opt_summary.append( 
                    pd.DataFrame(
                        OrderedDict(
                        atr_n=atr_n, 
                        maxloss_pct=maxloss_pct, 
                        stoploss_mode=g.params['stoploss_mode'],
                        trx_timing=g.params['trx_timing'],
                        cagr=cagr, mdd=mdd, sharpe=sharpe
                        ), 
                    index=[1], 
                    ),
                ignore_index=True,
                )
    print(opt_summary)
    out['close']=pos.close
    
#    out.plot()
    return out
    



#%%
#wr.write_report_md()
#%%

if __name__=="__main__": 
    #atr_n=int(input('Please enter parameter: atr_n: '))
    #for atr_n in range(12, 18):
    pass


原文地址:https://www.cnblogs.com/duan-qs/p/12927594.html