table=api.USData.get('美股產業對照表')
#從每個粗產業中 ,挑出一檔市值最大的"非etf"
ls =[]
for group in table.粗產業名稱.unique():
if group=='':
continue
symbol = table.loc[table[(table["粗產業名稱"] == group) & (table["是否為ETF"] == "0")]["市值(美元)"].idxmax()].股票代號
ls.append(symbol)
dic ={}
for symbol in ls:
table = api.USData.get('日K價量資料(個股、ETF)-單檔股票多個區間',symbol)
df = table.set_index('日期')[['開盤價','收盤價','成交量','最低價']]
df.columns=['Open','Close','Volume','Low']
#量創10日均量的兩倍
con1 = df['Volume'] > df['Volume'].shift(1).rolling(10).mean()*2
#收盤價 > 最低價*1.03
con2 = df['Close'] > df['Low']*1.03
pos = con1 &con2
df.loc[pos[pos==True].index,'sig']=True
#每檔5000美元
df['qty'] = np.around(5000/df['Open'])
#存入dic
dic[symbol] = df.reset_index()
#sig_value 用來計算止盈止損的對標欄位
#open_value 進場價格欄位
#close_value 出場價格欄位
benchmark =api.USData.get('日K價量資料(個股、ETF)-單檔股票多個區間','SPY').set_index('日期')['收盤價']
rp = api.backtest( data=dic ,
date='日期',
sig_value='Close',
open_value='Open', open_shift=True,
close_value='Open', close_shift=True,
longsig='sig',qty='qty',
moveloss=20,
fee=0.003/2 ,tax=0.0000051,
benchmark=benchmark)
table=api.USData.get('美股產業對照表')
#市值前30大的股票
ls =table[(table['是否為ETF']=='0')&(table['市值(美元)'].notnull())&(table.流通股數.notnull())].sort_values('市值(美元)',ascending=False)[:30].股票代號.tolist()
#計算macd
def ind_MACD(data, short_window=12 ,long_window = 26 ,macd_window = 9):
short_ema = data.ewm(span=short_window, adjust=False).mean()
short_ema[:short_window-1] = np.nan # 前 11 筆設為 NaN
long_ema = data.ewm(span=long_window, adjust=False).mean()
long_ema[:long_window-1] = np.nan # 前 25 筆設為 NaN
macd = short_ema -long_ema
macd_ema = macd.ewm(span=macd_window, adjust=False).mean()
macdhist = macd - macd_ema
return macd ,macd_ema ,macdhist
dic ={}
for symbol in ls:
table = api.USData.get('日K價量資料(個股、ETF)-單檔股票多個區間',symbol)
df = table.set_index('日期')[['開盤價','收盤價','成交量','最低價']]
df.columns=['Open','Close','Volume','Low']
macd ,macd_ema ,macdhist = ind_MACD(df['Close'], short_window=12 ,long_window = 26 ,macd_window = 9)
#低點3bar内的最低macdhist
low_point = macdhist.rolling(3).min()
#低點是60内的最低點
con1 = low_point ==low_point.rolling(60).min()
#連續兩期上升
con2 = (macdhist>macdhist.shift(1)) &(macdhist.shift(1)>macdhist.shift(2))
#hist<0
con3 = macdhist<0
#進場
bk = con1&con2&con3
con4 = (macdhist<macdhist.shift(1))& (macdhist.shift(1)<macdhist.shift(2))
#hist>0
con5 = macdhist>1.5
#出場
bp = con4&con5
#套用到sig
df.loc[bk[bk==True].index,'sig']=True
df.loc[bp[bp==True].index,'sig']=False
#每檔5000美元
df['qty'] = np.around(5000/df['Open'])
#存入dic
dic[symbol] = df.reset_index()
benchmark =api.USData.get('日K價量資料(個股、ETF)-單檔股票多個區間','SPY').set_index('日期')['收盤價']
rp = api.backtest( data=dic ,
date='日期',
sig_value='Close',
open_value='Open', open_shift=True,
close_value='Open', close_shift=True,
longsig='sig',qty='qty',
fee=0.003/2 ,tax=0.0000051,
benchmark=benchmark)
提供一系列方法展示對應數據。
| 參數 | 資料型態 | 說明 |
|---|---|---|
| data | dict(symbol:DataFrame) or DataFrame | 為資料本體,需為dataframe 或可為 dataframe 組成的dic |
| date | str | dataframe中代表"日期"欄位的column名稱。 |
| symbol | str | 指定在 DataFrame 中代表"股票代號"欄位的列名。如data為字典,則使用字典的鍵作為 `symbol`。 |
| sig_value | str | 設定用做停利停損判斷對象的"標準價"的column名稱,為必填欄位。 |
| open_value | str | 設定"進場價"的column名稱,如果沒設定將使用sig_value設定的欄位名稱。 |
| open_shift | bool | 默認為True,會在滿足信號後的下一根K棒執行進場;若為False,則在當根執行。 |
| close_value | str | 設定"出場價"的column名稱,如果沒設定將使用sig_value設定的欄位名稱。 |
| close_shift | bool | 默認為True,會在滿足信號後的下一根K棒執行出場;若為False,則在當根執行。 |
| longsig | str | 做多方向的"進場信號"的column名稱,longsig和shortsig至少需設定一個;值為True代表進場,False為出場,nan不進行任何行爲。 |
| longout | str | 做多方向的"出場信號"的column名稱,為longsig的補充欄位,非必填。值為True時代表出場。longsig和longout同時為True,依舊表示為出場。 |
| shortsig | str | 做空方向的"進場信號"的column名稱,longsig和shortsig至少需設定一個。值為True代表進場,False為出場,nan不進行任何行爲。 |
| shortout | str | 做空方向的"出場信號"的column名稱,為shortsig的補充欄位,非必填。值為True時代表出場。shortsig和shortout同時為True,依舊表示為出場。 |
| qty | int | 設定"股數"的column名稱,為必填欄位。 |
| tax | float | 交易稅率,默認為None將使用台灣交易規則的默認設置。默認規則為一般股票0.003、ETF為0.001、股票當沖0.0015-例如,設定為0.0005,在做多出場發生交易稅5bp,在做空時進場發生交易稅5bp。 美股需自行設定。 |
| fee | float | 手續費率,用於計算進場和出場時的手續費,如不填寫為0.00025。-例如,設定為0.00125,代表進場及出場各會發生手續費12.5bp。 |
| earn | float | 停利比率,表示當收益達到該比率時觸發停利。-例如,設定為 20 則代表停利為 20%。如果未指定,則不設定停利條件。 |
| loss | float | 停損比率,表示當虧損達到該比率時觸發停損。 -例如,設定為 20 則代表停損為 20%。如果未指定,則不設定停損條件。 |
| slippage | float | 滑點率,指在進場及出場時可能發生的往不利價格方向的變動量,默認為0。-例如,設定為0.001,代表進場及出場各會滑點10bp。 |
| moveloss | float | 設定"移動停利",計算邏輯是用進場後設定的sig_value的最大值與進場價格計算。 若未設定數值,則不啟用移動停損條件 例如: 多方,moveloss=10: 移動止損=max(進場後的sig_value1 ,sig_value2 ,.... ,sig_valueN) * (1-0.01 * moveloss) 當 sig_valueN < 移動止損,觸發離場信號。 空方,moveloss=10: 移動止損=min(進場後的sig_value1 ,sig_value2 ,.... ,sig_valueN) * (1+0.01 * moveloss) 當 sig_valueN > 移動止損,觸發離場信號。 |
| max_hold | float | 最大持有天數,表示持股的最大天數限制。 |
| continuous_wins | tuple or list | 連勝N次後,交易量增為M倍的設置。-例如,設定為 (3, 2) 表示連勝3次後,交易量變為原來的2倍。如果未指定,則不調整交易量。 |
| force_exit | int | 將列表裡的已持有股票在最後一根Kbar強制進行出場。 |
| benchmark | Series | -對標價格,index需為日期,避免因日期錯誤產生誤差。 |
| messages | bool | 是否顯示回測產出過程中的信息,默認為True。 |
| _maxtrades | int | 最大交易次數,若未設定則默認為10000次。 可自行設定此參數值。 |
將返回一個物件,封装了回測分析結果,並可使用以下方法展示對應數據。
| 方法 | 說明 |
|---|---|
| dashboard | 本次策略總績效報告儀錶板。 |
| trade | 交易明細。 |
| position | 每日持倉。 |
| daily | 每日帳戶損益。 |
| report | 策略績效報告。 |
| plotly | 顯示績效圖表。 |
| save | 將結果儲存在本地位置。 |