11点策略


策略总览

适用环境

比较适合上涨下跌趋势比较明确的时间。

大跌以后第一天,不宜于这个策略。大跌以后第一天,因为波动大,有可能会有人抄底。

核心逻辑

这个策略本质上是趋势跟踪策略,通过策略指标判断策略趋势,然后押注上涨或者下跌。

由于市场开盘价容易受到消息影响高开或者低开,因此判断趋势使用的是相对于开盘价的涨幅,这样就能避开消息的影响,只关注资金的趋势。

市场虽然可以交易到15点,但一般来说,上午是主动交易时间。

经过统计,11点前的交易资金量和11点后的交易资金量基本持平。但不同的地方在于:

11点前是主动交易,主动引导股市,主动去买入和卖出;
11点后是被动交易,看今天股市涨了或者跌了,才去交易。

就像我们以前大学里面,上午做作业的,都是主动学习的,我们下午做作业的,基本就是抄上午的人的作业,属于一群不爱学习的。

每日11点相对于开盘涨跌幅,基本可以代表当日的情绪情况。

策略信号

设定:

当日11点涨幅:T0

近4日11点涨幅加权值:avg_4 = ( T0 × 0.4 + T-1 × 0.3 + T-2 × 0.2 + T-3 × 0.1 )

做多:

T0 > 0 且 avg_4 > 0 且 ( T0 > 0.3% 或 avg_4 > 0.3% )

做空:

T0 < 0 且 avg_4 < 0

空仓:

不符合做多和做空的情况

导入包

from jqdata import *
from datetime import datetime,timedelta
import pandas as pd

方法

策略:获取交易信号

def get_signal(se):
    pct = 0.3
    
    #策略信号
    T0 = se['T-0']
    avg_4 = (se['T-0']*0.4+se['T-1']*0.3+se['T-2']*0.2+se['T-3']*0.1)
    
    '''
    # 原策略
    boolean = T0>pct/100 or avg_4>pct/100
    if boolean:
        return 1
    else:
        return -1
    '''
    
    # 做多
    boolean1 = T0>pct/100
    boolean2 = avg_4>0
    boolean3 = T0>0
    boolean4 = avg_4>pct/100
    boolean_long = (boolean1 and boolean2) or (boolean3 and boolean4)
    boolean_long = (boolean2 and boolean3) and (boolean1 or boolean4)
    
    # 做空
    boolean1 = avg_4<0
    boolean2 = T0<0
    boolean_short = (boolean1 and boolean2) #and (boolean1 or boolean4)
    
    if boolean_long:
        # 同时大于0.3%,做多
        return 1
    elif boolean_short:
        # 同时小于0,做空
        return -1
    else:
        # 其他情况,不做
        return 0

最大回测

def get_maxdown_ratio(df):
    se = df['cumprod_value']
    se = se.drop_duplicates(keep='last')
    df = se.to_frame('values')
    df['max2here'] = df['values'].expanding().max()
    df['dd2here'] = df['values'] / df['max2here']
    df['maxd2here'] = 1 - df['dd2here']
    
    return df#df['maxd2here'].max()

年化收益

def get_annual_return(df):
    start = df.index[0]
    end = df.index[-1]
    start_date = datetime.strptime(start,'%Y-%m-%d')
    end_date = datetime.strptime(end,'%Y-%m-%d')
    days = (end_date - start_date) / timedelta(1)
    cumprod_value = df['cumprod_value'].iloc[-1] / df['cumprod_value'].iloc[0] 
    annual = cumprod_value ** (1/(days/365)) - 1
    return annual

索提诺比率

def get_sortino(df):
    se = df['cumprod_value']
    
    start = df.index[0]
    end = df.index[-1]
    start_date = datetime.strptime(start,'%Y-%m-%d')
    end_date = datetime.strptime(end,'%Y-%m-%d')
    
    # 年化收益
    day_list = se.index.tolist()
    days = (end_date - start_date).days
    
    ann_r = (se.iloc[-1]/se.iloc[0])**(365/days) -1
    
    pct_change = se.pct_change()
    pct_change = pct_change.dropna()
    
    # 策略波下行波动率
    num = len(pct_change)
    se = pct_change - pct_change.mean() 
    se = se[se<0]
    vol = np.sqrt(((se)**2).sum()*250/(num))
    
    # 索提诺比率
    Sortino = (ann_r - 0.04) / vol
    
    return (Sortino)

设置

指数

index = '000852.XSHG'

securities_df = get_all_securities(types=['index'])
name = securities_df.loc[index].display_name      
index,name
('000852.XSHG', '中证1000指数')

时间

end = datetime.now()
start = end - timedelta(11*365)
# start = '2015-08-01'
start,end
(datetime.datetime(2011, 8, 29, 16, 7, 7, 854820),
 datetime.datetime(2022, 8, 26, 16, 7, 7, 854820))

数据准备

日数据

days_df = get_price(index,start_date = start,end_date = end ,fields= ['open','close'],fq = 'pre',panel=False)
days_df['day_change'] = days_df['close'].pct_change()
days_df = days_df.dropna()

分钟数据

实际的开始和结束时间

trade_dates = list(map(lambda x:x.strftime("%Y-%m-%d"),get_trade_days(start_date = days_df.index[0], end_date = days_df.index[-1])))

trade_dates[0],trade_dates[-1]
('2014-10-20', '2022-08-26')
data = []
for date in trade_dates[:]:
    # 每日分钟曲线
    minutes_df = get_price(index,start_date = date + " 09:00:00", end_date = date + " 15:00:00",fields=['close'],fq = 'pre',frequency='1m',panel=False)
    # 分钟
    minutes_df['time'] = list(map(lambda x:x.strftime('%H:%M'),minutes_df.index))
    
    # 开盘价
    open_price = days_df.loc[date,'open']
    
    # 11点和15点相对开盘涨跌幅
    close_1100 = minutes_df[minutes_df['time']=='11:00']['close'].iloc[0]
#     close_1100 = minutes_df[minutes_df['time']=='10:00']['close'].iloc[0]
    close_1500 = minutes_df[minutes_df['time']=='15:00']['close'].iloc[0]
    pct_change1 = close_1100 / open_price - 1 # 11点涨跌幅
    pct_change2 = close_1500 / open_price - 1 # 15点涨跌幅
    
    data.append([date,open_price,close_1100,close_1500,pct_change1,pct_change2])
    
minute_df = pd.DataFrame(data,columns=['date','close_0931','close_1100','close_1500','pct_change1','pct_change2'])

minute_df = minute_df.dropna()
minute_df.head()

date close_0931 close_1100 close_1500 pct_change1 pct_change2
0 2014-10-20 6068.78 6122.24 6154.52 0.008809 0.014128
1 2014-10-21 6153.02 6163.15 6103.01 0.001646 -0.008128
2 2014-10-22 6102.46 6117.28 6027.51 0.002429 -0.012282
3 2014-10-23 6009.84 5980.27 5930.48 -0.004920 -0.013205
4 2014-10-24 5930.57 5953.57 5941.93 0.003878 0.001915

下单信号以及下单后变动幅度

result_df = minute_df.copy()
# 信号:11点相对开盘涨幅
result_df['pct_signal'] = result_df['pct_change1']
df = result_df[['date','pct_signal','close_0931','close_1100']]
# 11点下单后到下一个交易日11点的变动
df['close_11_change'] = df['close_1100'].pct_change()
/opt/conda/lib/python3.6/site-packages/ipykernel_launcher.py:3: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  This is separate from the ipykernel package so we can avoid doing imports until
df.head()

date pct_signal close_0931 close_1100 close_11_change
0 2014-10-20 0.008809 6068.78 6122.24 NaN
1 2014-10-21 0.001646 6153.02 6163.15 0.006682
2 2014-10-22 0.002429 6102.46 6117.28 -0.007443
3 2014-10-23 -0.004920 6009.84 5980.27 -0.022397
4 2014-10-24 0.003878 5930.57 5953.57 -0.004465

最近4个交易日的交易信号

# 前面8个交易日的涨跌幅
days_list = list(range(0,4))
days_list.reverse()
for i in days_list:
    col_name = 'T-{}'.format(i)
    df[col_name] = df['pct_signal'].shift(i)

df.index = df.date

# 去掉重复的列:已经转换为T-0
df = df.drop(columns = 'pct_signal')

df = df.dropna()
/opt/conda/lib/python3.6/site-packages/ipykernel_launcher.py:6: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
df.head()

date close_0931 close_1100 close_11_change T-3 T-2 T-1 T-0
date
2014-10-23 2014-10-23 6009.84 5980.27 -0.022397 0.008809 0.001646 0.002429 -0.004920
2014-10-24 2014-10-24 5930.57 5953.57 -0.004465 0.001646 0.002429 -0.004920 0.003878
2014-10-27 2014-10-27 5927.15 5981.17 0.004636 0.002429 -0.004920 0.003878 0.009114
2014-10-28 2014-10-28 6021.65 6098.55 0.019625 -0.004920 0.003878 0.009114 0.012771
2014-10-29 2014-10-29 6179.46 6228.55 0.021317 0.003878 0.009114 0.012771 0.007944

回测

获取交易信号

# 获取交易信号
df['signal'] = df.apply(lambda x:get_signal(x),axis=1)

计算每次交易收益情况

position = 1
# 交易信号对应的涨跌幅
df['change'] = df['close_11_change'].shift(-1)

# 计算多空收益
df['profit_change'] = df['change'] * df['signal'] * position

# 计算净值
df['value'] = df['profit_change'] + 1

# 累计净值
df['cumprod_value'] = df['value'].cumprod()
df

date close_0931 close_1100 close_11_change T-3 T-2 T-1 T-0 signal change profit_change value cumprod_value
date
2014-10-23 2014-10-23 6009.8400 5980.2700 -0.022397 0.008809 0.001646 0.002429 -0.004920 -1 -0.004465 0.004465 1.004465 1.004465
2014-10-24 2014-10-24 5930.5700 5953.5700 -0.004465 0.001646 0.002429 -0.004920 0.003878 1 0.004636 0.004636 1.004636 1.009121
2014-10-27 2014-10-27 5927.1500 5981.1700 0.004636 0.002429 -0.004920 0.003878 0.009114 1 0.019625 0.019625 1.019625 1.028925
2014-10-28 2014-10-28 6021.6500 6098.5500 0.019625 -0.004920 0.003878 0.009114 0.012771 1 0.021317 0.021317 1.021317 1.050858
2014-10-29 2014-10-29 6179.4600 6228.5500 0.021317 0.003878 0.009114 0.012771 0.007944 1 0.008288 0.008288 1.008288 1.059567
2014-10-30 2014-10-30 6248.4700 6280.1700 0.008288 0.009114 0.012771 0.007944 0.005073 1 -0.010646 -0.010646 0.989354 1.048287
2014-10-31 2014-10-31 6242.8400 6213.3100 -0.010646 0.012771 0.007944 0.005073 -0.004730 0 0.005337 0.000000 1.000000 1.048287
2014-11-03 2014-11-03 6217.1000 6246.4700 0.005337 0.007944 0.005073 -0.004730 0.004724 1 0.000852 0.000852 1.000852 1.049180
2014-11-04 2014-11-04 6275.0000 6251.7900 0.000852 0.005073 -0.004730 0.004724 -0.003699 -1 -0.002946 0.002946 1.002946 1.052271
2014-11-05 2014-11-05 6222.9400 6233.3700 -0.002946 -0.004730 0.004724 -0.003699 0.001676 0 -0.001542 -0.000000 1.000000 1.052271
2014-11-06 2014-11-06 6223.0800 6223.7600 -0.001542 0.004724 -0.003699 0.001676 0.000109 0 0.012545 0.000000 1.000000 1.052271
2014-11-07 2014-11-07 6297.3500 6301.8400 0.012545 -0.003699 0.001676 0.000109 0.000713 0 -0.013302 -0.000000 1.000000 1.052271
2014-11-10 2014-11-10 6236.2000 6218.0100 -0.013302 0.001676 0.000109 0.000713 -0.002917 -1 -0.014958 0.014958 1.014958 1.068011
2014-11-11 2014-11-11 6252.3900 6125.0000 -0.014958 0.000109 0.000713 -0.002917 -0.020375 -1 -0.009523 0.009523 1.009523 1.078182
2014-11-12 2014-11-12 6005.8600 6066.6700 -0.009523 0.000713 -0.002917 -0.020375 0.010125 0 -0.008184 -0.000000 1.000000 1.078182
2014-11-13 2014-11-13 6116.9800 6017.0200 -0.008184 -0.002917 -0.020375 0.010125 -0.016341 -1 -0.002445 0.002445 1.002445 1.080818
2014-11-14 2014-11-14 6002.0500 6002.3100 -0.002445 -0.020375 0.010125 -0.016341 0.000043 0 0.014878 0.000000 1.000000 1.080818
2014-11-17 2014-11-17 6016.5400 6091.6100 0.014878 0.010125 -0.016341 0.000043 0.012477 1 0.003510 0.003510 1.003510 1.084611
2014-11-18 2014-11-18 6095.8700 6112.9900 0.003510 -0.016341 0.000043 0.012477 0.002808 1 0.006643 0.006643 1.006643 1.091817
2014-11-19 2014-11-19 6134.3700 6153.6000 0.006643 0.000043 0.012477 0.002808 0.003135 1 0.002881 0.002881 1.002881 1.094963
2014-11-20 2014-11-20 6174.8900 6171.3300 0.002881 0.012477 0.002808 0.003135 -0.000577 0 0.007347 0.000000 1.000000 1.094963
2014-11-21 2014-11-21 6183.4700 6216.6700 0.007347 0.002808 0.003135 -0.000577 0.005369 1 0.009679 0.009679 1.009679 1.105560
2014-11-24 2014-11-24 6281.5600 6276.8400 0.009679 0.003135 -0.000577 0.005369 -0.000751 0 0.011600 0.000000 1.000000 1.105560
2014-11-25 2014-11-25 6295.6800 6349.6500 0.011600 -0.000577 0.005369 -0.000751 0.008573 1 0.011610 0.011610 1.011610 1.118396
2014-11-26 2014-11-26 6400.5900 6423.3700 0.011610 0.005369 -0.000751 0.008573 0.003559 1 0.006595 0.006595 1.006595 1.125772
2014-11-27 2014-11-27 6450.5100 6465.7300 0.006595 -0.000751 0.008573 0.003559 0.002360 1 0.002399 0.002399 1.002399 1.128472
2014-11-28 2014-11-28 6476.5700 6481.2400 0.002399 0.008573 0.003559 0.002360 0.000721 0 -0.014803 -0.000000 1.000000 1.128472
2014-12-01 2014-12-01 6478.0000 6385.3000 -0.014803 0.003559 0.002360 0.000721 -0.014310 -1 0.011030 -0.011030 0.988970 1.116025
2014-12-02 2014-12-02 6385.9500 6455.7300 0.011030 0.002360 0.000721 -0.014310 0.010927 1 -0.007434 -0.007434 0.992566 1.107729
2014-12-03 2014-12-03 6465.4600 6407.7400 -0.007434 0.000721 -0.014310 0.010927 -0.008927 -1 0.022699 -0.022699 0.977301 1.082584
... ... ... ... ... ... ... ... ... ... ... ... ... ...
2022-07-18 2022-07-18 6868.3000 6907.9500 -0.008041 0.005218 0.015640 0.010761 0.005773 1 0.014721 0.014721 1.014721 326.941779
2022-07-19 2022-07-19 6956.8600 7009.6400 0.014721 0.015640 0.010761 0.005773 0.007587 1 0.011012 0.011012 1.011012 330.542055
2022-07-20 2022-07-20 7028.7900 7086.8300 0.011012 0.010761 0.005773 0.007587 0.008257 1 0.001918 0.001918 1.001918 331.175916
2022-07-21 2022-07-21 7098.2700 7100.4200 0.001918 0.005773 0.007587 0.008257 0.000303 1 -0.006566 -0.006566 0.993434 329.001478
2022-07-22 2022-07-22 7081.5600 7053.8000 -0.006566 0.007587 0.008257 0.000303 -0.003920 0 -0.004985 -0.000000 1.000000 329.001478
2022-07-25 2022-07-25 7037.7600 7018.6400 -0.004985 0.008257 0.000303 -0.003920 -0.002717 -1 -0.003777 0.003777 1.003777 330.244145
2022-07-26 2022-07-26 6949.1900 6992.1300 -0.003777 0.000303 -0.003920 -0.002717 0.006179 1 0.011367 0.011367 1.011367 333.998052
2022-07-27 2022-07-27 7018.2200 7071.6100 0.011367 -0.003920 -0.002717 0.006179 0.007607 1 0.016145 0.016145 1.016145 339.390396
2022-07-28 2022-07-28 7138.3200 7185.7800 0.016145 -0.002717 0.006179 0.007607 0.006649 1 -0.006264 -0.006264 0.993736 337.264536
2022-07-29 2022-07-29 7152.3300 7140.7700 -0.006264 0.006179 0.007607 0.006649 -0.001616 0 0.000804 0.000000 1.000000 337.264536
2022-08-01 2022-08-01 7100.7100 7146.5100 0.000804 0.007607 0.006649 -0.001616 0.006450 1 -0.031830 -0.031830 0.968170 326.529567
2022-08-02 2022-08-02 7098.1800 6919.0400 -0.031830 0.006649 -0.001616 0.006450 -0.025237 -1 0.013626 -0.013626 0.986374 322.080220
2022-08-03 2022-08-03 6968.2900 7013.3200 0.013626 -0.001616 0.006450 -0.025237 0.006462 0 -0.008554 -0.000000 1.000000 322.080220
2022-08-04 2022-08-04 6953.9800 6953.3300 -0.008554 0.006450 -0.025237 0.006462 -0.000093 -1 0.004904 -0.004904 0.995096 320.500699
2022-08-05 2022-08-05 6975.8900 6987.4300 0.004904 -0.025237 0.006462 -0.000093 0.001654 0 0.022290 0.000000 1.000000 320.500699
2022-08-08 2022-08-08 7082.5400 7143.1800 0.022290 0.006462 -0.000093 0.001654 0.008562 1 0.004637 0.004637 1.004637 321.986729
2022-08-09 2022-08-09 7168.9600 7176.3000 0.004637 -0.000093 0.001654 0.008562 0.001024 1 0.005415 0.005415 1.005415 323.730302
2022-08-10 2022-08-10 7183.1800 7215.1600 0.005415 0.001654 0.008562 0.001024 0.004452 1 0.007225 0.007225 1.007225 326.069275
2022-08-11 2022-08-11 7241.7300 7267.2900 0.007225 0.008562 0.001024 0.004452 0.003530 1 0.005006 0.005006 1.005006 327.701575
2022-08-12 2022-08-12 7287.6500 7303.6700 0.005006 0.001024 0.004452 0.003530 0.002198 0 -0.005790 -0.000000 1.000000 327.701575
2022-08-15 2022-08-15 7218.0900 7261.3800 -0.005790 0.004452 0.003530 0.002198 0.005997 1 0.011284 0.011284 1.011284 331.399477
2022-08-16 2022-08-16 7290.2400 7343.3200 0.011284 0.003530 0.002198 0.005997 0.007281 1 -0.004321 -0.004321 0.995679 329.967521
2022-08-17 2022-08-17 7330.4800 7311.5900 -0.004321 0.002198 0.005997 0.007281 -0.002577 0 0.003525 0.000000 1.000000 329.967521
2022-08-18 2022-08-18 7315.4100 7337.3600 0.003525 0.005997 0.007281 -0.002577 0.003001 1 -0.004868 -0.004868 0.995132 328.361162
2022-08-19 2022-08-19 7353.4300 7301.6400 -0.004868 0.007281 -0.002577 0.003001 -0.007043 -1 -0.007430 0.007430 1.007430 330.800832
2022-08-22 2022-08-22 7214.4800 7247.3900 -0.007430 -0.002577 0.003001 -0.007043 0.004562 1 0.003608 0.003608 1.003608 331.994426
2022-08-23 2022-08-23 7275.3800 7273.5400 0.003608 0.003001 -0.007043 0.004562 -0.000253 0 -0.019670 -0.000000 1.000000 331.994426
2022-08-24 2022-08-24 7312.5500 7130.4700 -0.019670 -0.007043 0.004562 -0.000253 -0.024900 -1 -0.017924 0.017924 1.017924 337.945255
2022-08-25 2022-08-25 7065.3400 7002.6600 -0.017924 0.004562 -0.000253 -0.024900 -0.008871 -1 0.010549 -0.010549 0.989451 334.380307
2022-08-26 2022-08-26 7032.6553 7076.5303 0.010549 -0.000253 -0.024900 -0.008871 0.006239 0 NaN NaN NaN NaN

1913 rows × 13 columns

df = df.dropna()
df.cumprod_value.iloc[-1]
334.38030705364923

导出回测结果到文件

today = pd.datetime.today().strftime("%Y-%m-%d")
df.to_csv('{}指数涨幅判断{}.csv'.format(name,today))

以指数作为比较基准

start = df.index[0]
end = df.index[-1]
index_price_df = get_price(index,start_date = start,end_date = end,fields=['close'],panel=False,fq=None)
index_price_df.index = list(map(lambda x:x.strftime("%Y-%m-%d"),index_price_df.index))
index_price_df['cumprod_value'] = df['cumprod_value']
index_price_df['close'] = index_price_df['close'] / index_price_df['close'].iloc[0]
index_price_df.index.tolist()[0]
'2014-10-23'
index_price_df

close cumprod_value
2014-10-23 1.000000 1.004465
2014-10-24 1.001931 1.009121
2014-10-27 1.012876 1.028925
2014-10-28 1.039321 1.050858
2014-10-29 1.053321 1.059567
2014-10-30 1.052459 1.048287
2014-10-31 1.046898 1.048287
2014-11-03 1.058260 1.049180
2014-11-04 1.050812 1.052271
2014-11-05 1.050041 1.052271
2014-11-06 1.060486 1.052271
2014-11-07 1.050197 1.052271
2014-11-10 1.053306 1.068011
2014-11-11 1.015601 1.078182
2014-11-12 1.031967 1.078182
2014-11-13 1.015732 1.080818
2014-11-14 1.013316 1.080818
2014-11-17 1.028724 1.084611
2014-11-18 1.035248 1.091817
2014-11-19 1.044361 1.094963
2014-11-20 1.043072 1.094963
2014-11-21 1.052321 1.105560
2014-11-24 1.061132 1.105560
2014-11-25 1.077896 1.118396
2014-11-26 1.085096 1.125772
2014-11-27 1.091411 1.128472
2014-11-28 1.092342 1.128472
2014-12-01 1.077899 1.116025
2014-12-02 1.088876 1.107729
2014-12-03 1.098387 1.082584
... ... ...
2022-07-15 1.155525 322.198781
2022-07-18 1.172575 326.941779
2022-07-19 1.181914 330.542055
2022-07-20 1.198908 331.175916
2022-07-21 1.193038 329.001478
2022-07-22 1.186177 329.001478
2022-07-25 1.171728 330.244145
2022-07-26 1.184966 333.998052
2022-07-27 1.197109 339.390396
2022-07-28 1.205670 337.264536
2022-07-29 1.200144 337.264536
2022-08-01 1.210770 326.529567
2022-08-02 1.173257 322.080220
2022-08-03 1.166292 322.080220
2022-08-04 1.173650 320.500699
2022-08-05 1.195519 320.500699
2022-08-08 1.210039 321.986729
2022-08-09 1.215315 323.730302
2022-08-10 1.216104 326.069275
2022-08-11 1.230000 327.701575
2022-08-12 1.218928 327.701575
2022-08-15 1.228147 331.399477
2022-08-16 1.235080 329.967521
2022-08-17 1.235763 329.967521
2022-08-18 1.239603 328.361162
2022-08-19 1.219869 330.800832
2022-08-22 1.229003 331.994426
2022-08-23 1.231944 331.994426
2022-08-24 1.186988 337.945255
2022-08-25 1.183093 334.380307

1912 rows × 2 columns

最大回撤

max_down_df = get_maxdown_ratio(df)
max_down = max_down_df['maxd2here'].max()
max_down
0.203109424118747
index_price_df['max_down'] = max_down_df['maxd2here']

年化收益

annual = get_annual_return(df)
annual
1.0968404462878532

索提诺比率

sortino = get_sortino(df)
sortino
6.645217051360931

总体胜率

total_win_ratio = len(df[df['profit_change']>0])/len(df[df['profit_change']!=0])
total_win_ratio
0.62

做多情况

# 做多数量
long_signal = df[df['signal']==1]
# 胜率
long_win_ratio = len(long_signal[long_signal['profit_change']>0])/len(long_signal)
long_win_ratio
# 盈亏比
long_win_lost = abs(long_signal['profit_change'][long_signal['profit_change']>0].mean() / long_signal['profit_change'][long_signal['profit_change']<0].mean())

做空情况

short_signal = df[df['signal']==-1]

# 胜率
short_win_ratio = len(short_signal[short_signal['profit_change']>0])/len(short_signal)

short_win_lost = abs(short_signal['profit_change'][short_signal['profit_change']>0].mean() / short_signal['profit_change'][short_signal['profit_change']<0].mean()) 
len(short_signal),"%.2f%%"%(round(short_win_ratio*100,2)),round(short_win_lost,2)
(560, '57.50%', 1.38)

绘图

import matplotlib.pyplot as plt
plt.rcParams['axes.unicode_minus']=False

plt.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认字体

fig = plt.figure(figsize=(16,5))  
fig.set_facecolor('white')
ax1 = fig.add_subplot(111)

ax1.grid(True)

tmp = index_price_df.copy()
# tmp = tmp.head(500)
# tmp = tmp.loc["2022-01-01":].dropna()
tmp['close']/= tmp['close'].iloc[0]
tmp['cumprod_value']/= tmp['cumprod_value'].iloc[0]


x = tmp.index.tolist()
y1 = tmp.cumprod_value.tolist()
y2 = tmp.close.tolist()
y3 = tmp.max_down.tolist()

ax1.plot(x,y1,color='red', label = '指数多空交易净值')
ax1.set_title('指数多空交易与{}点位'.format(name))

xticklist = []
xlabellist = []

date_list = x
num = int(len(date_list) / 10)
for idx,date in enumerate(date_list):
    if idx % num == 0 :
        xticklist.append(idx)
        xlabellist.append(date)

ax1.set_xticks(xticklist)  
ax1.set_xticklabels(xlabellist, rotation=0, fontsize='large')  
ax1.set_ylabel(u'指数多空交易净值', fontsize='large')
ax1.set_xlabel(u'日期', fontsize='large')    

ax1.plot(x,y2,label='{}'.format(name))
ax1.set_ylabel(u'{}'.format(name), fontsize='large')

#for num in date_num_list:
ax2 = ax1.twinx()
ax2.set_xticks(xticklist)  
ax2.set_xticklabels(xlabellist, rotation=0, fontsize='large')  
ax2.bar(x,y3,color='gray',label='最大回撤')
ax2.set_ylabel(u'最大回撤', fontsize='large')
#ax2.axhline(y=0,color='black',ls='-')

ax1.legend(loc=2, ncol=3, shadow=True)
ax2.legend(loc=4, ncol=3, shadow=True)

plt.show()

png

统计结果

cols = ['类型','数量','胜率','盈亏比']
data = [
    ["做多",len(long_signal),"%.2f%%"%(round(long_win_ratio*100,2)),round(long_win_lost,2)],
    ["做空",len(short_signal),"%.2f%%"%(round(short_win_ratio*100,2)),round(short_win_lost,2)],
    ["空仓",len(df)-len(long_signal)-len(short_signal),0,0]
]
pd.DataFrame(data,columns = cols)

类型 数量 胜率 盈亏比
0 做多 740 65.41% 1.23
1 做空 560 57.50% 1.38
2 空仓 612 0 0.00
cols = ['累计净值','年化收益','最大回撤','索提诺比率']
data = [[round(df.cumprod_value.iloc[-1],2),"%.2f%%"%(round(annual*100,2)),
         "%.2f%%"%(round(max_down*100,2)),(round(sortino,2))]]
pd.DataFrame(data,columns = cols)

累计净值 年化收益 最大回撤 索提诺比率
0 334.38 109.68% 20.31% 6.65

文章作者: 止一之路
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 止一之路 !
评论
  目录