在數字貨幣量化領域的資料實在是太少了,我總結了一下我的經驗(以火幣交易所爲例)以供小白參考
第一步:申請api key和secret,
第二步:查看交易所的api文檔(https://huobiapi.github.io/docs/spot/v1/cn/#185368440e)
第三步:這裏其實是困擾很多小白的一部,就是拿到了api不知道該怎麼用,首先火幣提供了不同語言版本的sdk,可以利用這些sdk中提供的方法來查詢歷史k線,盤口情況,實時價格以及常用的各種信息,當然也可以選擇一些封裝好的第三方庫比如ccxt,來實現上述數據的獲取。一般來說ccxt這種庫會對數據格式進行進一步處理,使用起來方便,而火幣原生的sdk只是提供方法,後面的數據處理得自己實現,就比如原生sdk獲取的歷史k線是按時間降序排序的,你計算ma的時候還要自己重新排序,但如果想要實現一個量化系統的話還是建議使用sdk好一點,自己寫輪子方便調用
第四步:就是把自己的交易邏輯用代碼實現,比如使用雙均線策略,
huobipro = ccxt.huobipro({ 'apiKey': '', 'secret': '', })
先使用ccxt獲取交易所的實例,然後獲取歷史k線,得到的數據使用dataframe格式接受
huobipro.fetch_ohlcv(symbol=symbol, limit=limit_num, timeframe=timeframe)
然後利用pandas提供的函數計算MA,
df['median_short'] = df['close'].rolling(n_short, min_periods=1).mean()
df['median_long'] = df['close'].rolling(n_long, min_periods=1).mean()
然後再找出買入賣出信號,
# 找出買入信號 condition1 = df['median_short'] > df['median_long'] # 短均線上穿長均線 condition2 = df['median_short'].shift(1) <= df['median_long'].shift(1) df.loc[condition1 & condition2, 'signal'] = 1 # 產生買入信號的k線標記爲1 # 找出賣出信號 condition1 = df['median_short'] < df['median_long'] # 短均線上穿長均線 condition2 = df['median_short'].shift(1) >= df['median_long'].shift(1) df.loc[condition1 & condition2, 'signal'] = 0 # 產生賣出信號的k線標記爲0
有了交易信號,就可以獲取信號,再判斷進行下單(huobipro.create_limit_buy/sell_order()了)
第五步:其實第四步就可以交易了,第五步是回測,一般來說先回測再根據回測結果選用策略,最後才進行實盤
回測分析的相關有很多種,在這方面我也不是很懂,目前我還是習慣用累計利潤來進行分析,
# 由signal計算出實際的每天持倉 df['pos'] = df['signal'].shift() df['pos'].fillna(method='ffill', inplace=True) df['pos'].fillna(value=0, inplace=True)
到這裏持倉信號就有了,就可以根據持倉和歷史k線的價格計算累計利潤了,
df['change'] = df['close'].pct_change(1) # 根據收盤價計算漲跌幅 df['by_at_open_change'] = df['close'] / df['open'] - 1 # 開盤買入到收盤的漲跌幅 df['sell_next_open_change'] = df['open'].shift(-1) / df['close'] - 1 # 這根收盤到下根開盤的漲跌幅 df.at[len(df) - 1, 'sell_next_open_change'] = 0 # 補全空值 df.at[4, 'B'] # 選取開倉條件 condition1 = df['pos'] == 1 condition2 = df['pos'] != df['pos'].shift(1) open_pos_condition = condition1 & condition2 # 選取平倉條件 condition1 = df['pos'] == 0 condition2 = df['pos'] != df['pos'].shift(1) close_pos_condition = condition1 & condition2 # 對每次交易進行分組 df.loc[open_pos_condition, 'start_time'] = df['open_time'] df['start_time'].fillna(method='ffill', inplace=True) df.loc[df['pos'] == 0, 'start_time'] = pd.NaT init_cash = 1000 # 初始資金 # 計算倉位變動 # 開倉時倉位 df.loc[open_pos_condition, 'position'] = init_cash * (1 + df['by_at_open_change']) group_num = len(df.groupby('start_time')) if group_num > 1: temp = df.groupby('start_time').apply(lambda x: x['close'] / x.iloc[0]['close'] * x.iloc[0]['position']) temp = temp.reset_index(level=[0]) df['position'] = temp['close'] df['position_max'] = df['position'] * df['high'] / df['close'] df['position_min'] = df['position'] * df['low'] / df['close'] # #平倉時的倉位 # df.loc[close_pos_condition,'position']*=(1+df.loc[close_pos_condition,'sell_next_open_change']) # 計算持倉利潤 df['porfit'] = (df['position'] - init_cash) * df['pos'] # 持倉利潤或虧損 # df.loc[df['pos']==1,'porfit_min']=(df['position_min']-init_cash)*df['pos'] #最小持倉盈利或虧損 # df.loc[df['pos']==0,'porfit_max']=(df['position_max']-init_cash)*df['pos'] # 計算實際資金量 df['cash'] = init_cash + df['porfit'] # 實際資金 # 計算資金曲線 df['equity_change'] = df['cash'].pct_change() # 開倉日收益率 df.loc[open_pos_condition, 'equity_change'] = df.loc[open_pos_condition, 'cash'] / init_cash - 1 df['equity_change'].fillna(value=0, inplace=True) df['equity_curve'] = (1 + df['equity_change']).cumprod() df['equity_curve'] = df['equity_curve'] * init_cash
從回測結果來看,雙均線策略比較喫單邊行情,震盪行情的話基本就是送手續費,而且比較適合大週期,日線級別啥的,不適合高頻交易,以bsv爲例,bsv是回測結果比較好的
實際走勢:
以投入1000u爲例,不考慮手續費的情況下,每天的資金情況如回測結果所示,最小640,最大10521,十倍,基本算是約等於bsv的最大漲幅,但還有很多小波段沒喫到,而且週期算是比較長的,btc回測也有3倍左右,最慘的是山寨,基本都是虧損
嗯,先寫這麼多,後面有想法了再更,可能是可視化回測方面的
可以看到其自上線最低價爲49.17,最高價爲455.55,最大漲幅爲9.26倍.如果2018年12月6號91買入,現價192.5,持倉到現在利潤約爲2.11倍,而該系統的收益爲8.43倍.也就是說該系統的雙均線策略遠遠領先不操作的收益.但是也應該看到該幣種最大漲幅爲9.26倍,該策略尚未領先其最大漲幅,
可以看到其自上線最低價爲49.17,最高價爲455.55,最大漲幅爲9.26倍.如果2018年12月6號91買入,現價192.5,持倉到現在利潤約爲2.11倍,而該系統的收益爲8.43倍.也就是說該系統的雙均線策略遠遠領先不操作的收益.但是也應該看到該幣種最大漲幅爲9.26倍,該策略尚未領先其最大漲幅,