先進的なプラットフォーム研究 Python データ分析&戦略バックテスト

作者: リン・ハーンニナバダス作成日: 2022-04-13 09:12:47,更新日: 2022-04-28 11:06:13

先進的なプラットフォーム研究 Python データ分析と戦略 バックテスト.ipynb

先進的なプラットフォーム研究

FMZには,ユーザがプラットフォーム API を熟知し,戦略研究を行うのを助ける jupyter ノートブックが内蔵されており,Python3 C++11/17 と Javascript の学習環境をサポートしている.Notebook+Python はデータ分析と戦略研究にほとんど不可欠な非常に強力なツールである.FMZ プラットフォームに付随するバックテストは非常に有用であるが,複雑で大量のデータを持つ戦略には適していない.この記事では,jupyter ノートブックを使用するいくつかの高度なスキルを紹介し,ランダムペア取引とマルチペア取引戦略のバックテストを実現する.

ユピーターの使用

FMZ内の研究環境は使用可能だが,ネットワーク接続は不便である.ノートブックと数学計算のために一般的に使用される関連ライブラリを含むアナコンダ3を自分のデバイスにインストールすることが推奨される.ローカルネットワーク環境を共有し,より優れたパフォーマンスを有する.またGoogleコラボを使用することが推奨される.いくつかのストレージ制限があるにもかかわらず,無料で強力で,ロボット学習に関連する研究に適している.

チュートリアル

Notebook と Python の特定の使用スキルのための多くのオンラインチュートリアルがあります. Python の定量化や jupyter notebook のチュートリアルなどのキーワードを検索することで多くの情報を見つけることができます. クローラー,データ処理,バックテスト,戦略設計,プロティングなどの一連の基礎を学び,マスターする必要があります.

データ取得

プラットフォームは一般的にKラインを履歴データで取得するためのAPIを提供し,一部のプラットフォームは取引ごとに実行取引のデータも提供しています.データを取得し保存するためにクローラーを使用する必要があります.また,プラットフォームによって直接送られたデータを受信し,ローカルデータベースストレージを作成することもできます.

次に,Binanceで永続契約のK線データを取得して保存する方法を示します.

まず,Binance Perpetual Swapのドキュメントを探してください.https://binance-docs.github.io/apidocs/futures/cn/#c59e471e81. 必要なパラメータと返されたデータフォーマットを見ることができます. 通常,APIによって取得されるKラインの数は限られており,Binanceは最大1000個がありますので,ループイテレーションで取得する必要があります.他のプラットフォームの状況はBinanceに類似しています. ネットワークは海外ネットワークに接続する必要があります (中国の国内ネットワークと比較して) をクロールするためにKライン.

Binanceがサポートする期間:1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,1M

[24]: 共同ライブラリへの輸入要求 #ネットワーク要求 日時 輸入日,日時 輸入時間 パンダをPDとして輸入 [160]では: def GetKlines ((symbol=BTC,start=2020-8-10,end=2021-8-10,period=1h): クライン = [] start_time = int(time.mktime(datetime.strptime(start, %Y-%m-%d).timetuple())) *1000 end_time = int ((time.mktime ((datetime.strptime ((end, %Y-%m-%d).時間倍数))) *1000 start_time < end_time: start_time < end_time: start_time < end_time: start_time < end_time: start_time < end_time: start_time < end_time > end_time: start_time < end_time > end_time > end_time > end_time > end_time res = requests.get ((https://fapi.binance.com/fapi/v1/klines?symbol=%sUSDT&interval=%s&startTime=%s&limit=1000% ((symbol,period,start_time)) res_list = res.json() クラインズ += res_list #print ((datetime.utcfromtimestamp ((start_time/1000).strftime ((%Y-%m-%d %H:%M:%S),len ((res_list)) start_time = res_list[-1][0] return pd.DataFrame ((Klines,columns=[time,open,high,low,close,amount,end_time,volume,count,buy_amount,buy_volume,null]).astype ((float) [85]: df = GetKlines ((symbol=BTC,start=2021-1-1,end=2021-8-10,period=1h)

パンダライブラリ内の機能を利用してデータを保存・読み取ることができます.フォーマットはcsvで,Excelソフトウェアで直接開くことができます.

最高価格,最低価格,オープン価格,終了価格,実行量に加えて,Binanceが返したKラインデータには,取引総額,イニシアティブ購入金額,実行金額なども含まれます.これらは戦略を構築するために使用できる貴重な情報です.

[86]: df.to_csv ((btc_klines.csv) df = pd.read_csv ((btc_klines.csv,index_col=0) [87]: df アウト[87]: ほら ほら ほら ほら ほら ほら ほら ほら ほら ほら ほら... オープン時間 高低 閉じる金額 終了時間 ボリューム数 buy_amount buy_volume null 0 1596988800000 11575.08 11642.00 11566.07 11591.37 6541.466 1596992399999 7.592336e+07 25724 3127.898 3.630633e+07 0 1 1596992400000 11591.39 11610.23 11526.90 11534.39 6969.252 1596995999999 8.057780e+07 27403 3390.424 3.920162e+07 0 2 1596996000000 11534.39 11656.69 11527.93 11641.07 6439.365 1596999599999 7.469135e+07 25403 3446.186 3.997906e+07 0 3 1596999600000 11641.06 11665.90 11624.20 11635.30 3911.582 1597003199999 4.555459e+07 17820 1842.413 2.145768e+07 0 4 1597003200000 11635.29 11684.00 11635.29 11673.81 3461.004 1597006799999 4.036804e+07 15513 1660.575 1.936981e+07 0 ............................................................................................................................................................................................................................................................ 8805 1628658000000 45627.72 45894.53 45540.00 45801.45 10296.202 1628661599999 4.710187e+08 112187 4988.565 2.282399e+08 0 8806 1628661600000 45801.46 46270.00 45800.01 46087.86 26409.962 1628665199999 1.215164e+09 247170 13696.301 6.302708e+08 0 8807 1628665200000 46087.87 46450.00 46087.87 46367.38 23969.309 1628668799999 1.110210e+09 232348 11990.951 5.554267e+08 0 8808 1628668800000 46367.37 46643.13 46002.01 46217.01 23472.769 1628672399999 1.086549e+09 229533 12334.292 5.711837e+08 0 8809 1628672400000 46217.01 46329.69 46046.54 46297.16 6579.477 1628675999999 3.039580e+08 78812 3313.055 1.530718e+08 0 ほら 8810 行 × 12 列

ほら [88]: df.index = pd.to_datetime ((df.time,unit=ms) #インデックスを日付に変換します. これはプロットするのに便利です. [89]: df.close.plot ((figsize=(15,6),グリッド = True); #close価格 アウト[89]:img[92]: (df.buy_amount.rolling(150).mean() /df.amount.rolling(150.mean (()).plot ((figsize=(15,6),grid = True); #フラット後,イニシアティブ購入金額の割合 基本的には,価格上昇の状況に対応しますが,長期平均は49%です. 出場[92]:img[93]: (df[count].rolling ((100).mean (()).plot ((figsize=(15,6),grid = True);#フラット後に実行された金額,そして市場コートは低い場所に準備されることがあります. アウト[1]:img

バックテストエンジン

前回の記事では,Pythonのバックテストエンジンも提供されていましたが,ここでは最適化されたバージョンです.USDT (または他の引換通貨のマージング) 永久契約はスポット契約と非常に似ています.違いは,永久契約はレバレッジされ,負の金額を保持することができ (ショートに相当) バックテストエンジンを共有できることです.暗号のマージング配送契約は通貨で決済され,特定のバックテストを必要とするため,特別です.

ここでは,マルチシンボルスポットまたはマルチシンボル永久バックテストを実装できる簡単な例が示されています.多くの詳細は無視されています.例えば,先物レバレッジ,マージン占有,資金調達率,清算メカニズム,市場作成およびオーダーテイカー取引,およびオーダーメンテナンスなど.しかし,通常は通常のバックテスト結果に影響しません.そして,マッチングの価格と量,アカウント更新はすべて外部から輸入する必要があります.読者はこれを改善することができます.

交換クラス紹介

  • account:USDT は,必要でないベース通貨を示します. realised_profit: すでに実現した利益と損失; unrealised_profit: まだ実現されていない利益と損失;合計: 総資本;手数料: 処理手数料.他の取引ペアの場合は,金額 (ショートする場合マイナス数); hold_price: 保有価格;価値: 保有価値;価格: 現在の価格.

  • trade_symbols: 取引ペアの配列; 1つの取引ペアでパスすることもできます. デフォルトのコート通貨はUSDTですが,他のコート通貨シンボルをバックテストに使用することもできます.

  • 料金:手渡し料金.単純に言えば,作者と受取者を区別しない.

  • initial_balance: 初期資産; デフォルト取引ペアの初期金額は0である.

  • 購入機能: 購入,これは,マッチングメカニズムなしで,永続契約の長期化と短期化に対応しています.

  • 販売機能: 販売する

  • アップデート機能:すべての取引ペアの価格辞書に転送する必要があるアカウント情報を更新する. [98]: クラス 交換:

    def init(自己, trade_symbols, fees=0.0004, initial_balance=10000) self.initial_balance = 初期_バランス #初期バランス self.fee = 料金 self.trade_symbols = trade_symbols 取引する self.account = {USDT:{実現_利益:0, 非実現_利益:0, :初期_残高, 手数:0}} trade_symbols のシンボルについては: self.account[symbol] = {金額:0, 保持価格:0, 価値:0, 価格:0, 実現利益:0,実現しない利益:0,手数料:0}

    def 取引 (自己,シンボル,方向,価格,金額):

      cover_amount = 0 if direction*self.account[symbol]['amount'] >=0 else min(abs(self.account[symbol]['amount']), amount)
      open_amount = amount - cover_amount
      self.account['USDT']['realised_profit'] -= price*amount*self.fee #take out the fee 
      self.account['USDT']['fee'] += price*amount*self.fee
      self.account[symbol]['fee'] += price*amount*self.fee
    
      if cover_amount > 0: #close first 
          self.account['USDT']['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount  #profit 
          self.account[symbol]['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount
          
          self.account[symbol]['amount'] -= -direction*cover_amount
          self.account[symbol]['hold_price'] = 0 if self.account[symbol]['amount'] == 0 else self.account[symbol]['hold_price']
          
      if open_amount > 0:
          total_cost = self.account[symbol]['hold_price']*direction*self.account[symbol]['amount'] + price*open_amount
          total_amount = direction*self.account[symbol]['amount']+open_amount
          
          self.account[symbol]['hold_price'] = total_cost/total_amount
          self.account[symbol]['amount'] += direction*open_amount
    

    def 購入 (自己,シンボル,価格,金額):self.Trade(符号 1,価格,金額)

    def 売る (自己,シンボル,価格,金額):self.Trade(符号 -1,価格,金額)

    def Update ((self, close_price): #資産を更新する 自己口座[USDT][未実現_利益] = 0 self.trade_symbols のシンボルについては: self.account[symbol][unrealised_profit] = (close_price[symbol] - self.account[symbol][hold_price]) *self.account[symbol][amount] (閉じる価格[symbol] - 自己口座[symbol][保持価格]) self.account[シンボル][価格] = close_price[シンボル] self.account[シンボル][value] = abs(self.account[シンボル][金額]) *close_price[シンボル] 自己口座[USDT][未実現_利益] +=自己口座[シンボル][未実現_利益] self.account[USDT][total] = round ((self.account[USDT][realised_profit] + self.initial_balance + self.account[USDT][unrealised_profit],6) 丸めること [117]: テストでは,プラットフォームがUSDT・マージンかスポットかに関わっていないことがわかります. 実際,結果は同じです. e = Exchange([BTC], fees=0.0004, initial_balance=10000) #Exchangeオブジェクトを作成し, BTCの取引ペアを1つだけ e.BTCを4万円で購入する. e.BTCを41,000で売る. e.Update (({BTC:41000}) #アカウント情報を更新する print ((e.account) #最終的な口座情報 print (("利益: ',丸い ((e.アカウント[USDT][合計]-e.初期_残高,2)) Out[117]:{USDT: {実現した_利益: 96.76, 実現しなかった_利益: 0.0, 合計: 10096.76, 手数料: 3.24}, BTC: {金額: 0.0, 保有価格: 0, 価値: 0.0, 価格:000, 41 実現した_利益: 100.0, 実現しなかった_利益: 0.0, 手数料: 3.24}} 利益: 96.76

グリッド戦略 バックテスト

まず,古典的な永続格子戦略をバックテストしましょう. この戦略は最近私たちのプラットフォームで非常に人気があります. 現金格子1と比較して,通貨を保持する必要はありませんし,レバレッジを追加することができます. これは現金格子1よりもはるかに便利です. しかし,直接バックテストできないため,通貨シンボルを選択するのに有利ではありません. ここで,バックテストエンジンを今すぐ使用します.

Liveのトップには2021年4月4日から開始された公式ボットがあります.ポジション値は150,グリッド間隔は0.01,現在の利益は3600USDTです.同じパラメータと5minKラインをバックテストする場合は,利益は3937USDTです.ボットの開始時のポジション値は150USDT未満なので,結果はかなり正確です.グリッド間隔を0.005に変更すると,利益は5226Uになります. 0.005のグリッド間隔は明らかに0.01よりもより良いパラメータです.それを調べるためにバックテストする必要があります.

K線期間が短くなるほど,対応するバックテスト結果は正確になり,必要なデータの量は大きくなります.読者は,バックテストしたい取引ペアにシンボルのパラメータを変更してみることができます.

[241]: 記号 = TRX df = GetKlines ((symbol=symbol,start=2021-4-4,end=2021-8-11,period=5m) [286]: 値 = 150 pct = 0.01

e = 交換 (※[シンボル],手数料=0.0002,初期_残高=10000) init_price = df.loc[0,close] res_list = [] #中間の結果を保存するために使用されます df.iterrowsの行については (): kline = row [1] #これは1つのKラインをテストし,1つの購入オーダーまたは1つの販売オーダーしか得ません.これはあまり正確ではありません. buy_price = (value / pct - value) / ((value / pct) / init_price + e.account[symbol][amount]) #セールオーダーの価格,それはメーカーの実行であるため,最終的なマッチング価格でもあります sell_price = (value / pct + value) / ((value / pct) / init_price + e.account[symbol][amount])

if kline.low < buy_price: #the lowest price of K-line is less than the current maker price; the buy order is executed 
    e.Buy(symbol,buy_price,value/buy_price)
if kline.high > sell_price:
    e.Sell(symbol,sell_price,value/sell_price)
e.Update({symbol:kline.close})
res_list.append([kline.time, kline.close, e.account[symbol]['amount'], e.account['USDT']['total']-e.initial_balance])

res = pd.DataFrame ((data=res_list, columns=[時間,価格,金額,利益]) res.index = pd.to_datetime (res.time,unit=ms) [287]: e.口座 [287]:{USDT: {実現_利益: 3866.633149565143, 未実現利益: 70.54622281993666 合計: 13937.179372 税金: 177.51000000000596 TRX: {金額: 36497.43208747655, 保持価格: 0.08203709078461048 : 3064.689372385406 価格: 0.08397 実現した利益: 4044.143149565462, 未実現利益: 70.54622281993666 料: 177.51000000000596}} [288]: res.profit.plot ((figsize=(15,6),グリッド = True) 外出[288]:img[170]では: res.price.plot ((figsize=(15,6),グリッド = True); #close価格 出場[170]:img

スポットバランス戦略 バックテスト

このタイプの戦略も比較的人気がありますが,FMZプラットフォームはマルチシンボルの戦略をバックテストするのにあまり良くないので,このバックテストエンジンを使って試してみてください.我々は4つの主流通貨シンボル,BTC,ETH,LTC,およびXRPを選択し,それぞれ市場価値の25%を設定し,1%の偏差をバランスします.

まず,過去1年の4つのシンボルの閉じる価格を取得します. ETHが最大値上昇し,他の3つは同様の上昇を示しています.これらの4つのシンボルを平均的に保持すると,最終純価値は4.5です.バックテスト後,均衡戦略は,わずかに向上した5.3の最終純価値を持っています.

[211]: 記号 = [BTC,ETH,LTC,XRP] データ = {} 符号の中の符号については: df = GetKlines ((symbol=symbol,start=2020-8-11,end=2021-8-11,period=1h) データ[シンボル] = df.close [291]: df = pd.DataFrame (([データ[シンボル].シンボルのシンボルの値],index=シンボル).T [302]: e = 交換 (符号,手数料=0.0004,初期_残高=10000) res_list = [] df.iterrowsの行について: 価格 = 行[1] 合計 = e.アカウント[USDT][合計] e.価格更新 符号の中の符号については: pct = e.アカウント[シンボル][]/合計 pct > 0.26 となった場合 e.販売 (符号,価格 (符号),点 (0.25) *合計/価格 (符号) pct < 0.24 の場合: e.購入 (符号,価格 (符号),0.25%) *合計/価格 (符号) res_list.append (([e.account[symbol][value] シンボルのためのシンボル] + [e.account[USDT][total]]) res = pd.DataFrame ((data=res_list, columns=symbols+[total]) [303]: (df/df.iloc[0,:]).plot ((figsize=(15,6),grid = True); #trandを正規化によってプロットする 出場[303]:img[304]: (res.total/10000-(df/df.iloc[0,:]).mean(axis=1)).plot(figsize=(15,6),grid = True); #効果を拡大する 出場[304]:img

カメの戦略

カメ戦略は,ポジションを追加するための完全なストップ・ロスのロジックを含む古典的なトレンド戦略です.詳細については,以下を参照してください.https://zhuanlan.zhihu.com/p/27987938バックテストのためにシンプルなバージョンを実行します.

トートルストラテジーの期間は戦略に大きな影響を持ち,あまりにも短い期間を選択することは望ましくない. ここでは6hを選択する. ドンチアンチャネル期間は5で選択し,ポジション比率はバックテストに従って0.003で選択する. 価格がチャネルのアップバンドを突破して1ユニットロングポジションを開くとき,そしてポジションを開いた後に価格が0.3波動性で上昇し続けると, 1ユニットを追加し,価格が損失を止めるために最新のオープン価格の波動性2.5を下回る.ショートオーダーの原則は同じである. ETHの大きな牛市場により,トートルストラテジーはメイントレンドを捕捉し,最終的に27倍の利益を達成し,期間中に最大レバレッジが4倍になる.

カメ戦略のパラメータは,期間と密接に関連しており,バックテストによって選択する必要があります.また,高リスクを避けるために,各時間のオープンポジションの単位が大きすぎないように注意する必要があります.

最終的な純価値チャートから,亀策は長期戦略であり,その間に3〜4ヶ月間利益がない場合があり,繰り返しストップ損失がある場合があることがわかりますが,一方で大きな市場価格が上がると,亀策はトレンドを利用して大きなポジションを蓄積し,トレンドの終わりまで維持し,多くの利益を得ることができます.上昇の終わりには,戦略は多くのポジションを蓄積します.この時点で,波動性は比較的大きくなり,多くの場合大きな利益が引き上げられます.亀策を使用するには,その欠点と忍耐を受け入れることが必要です.

[424]: 記号 = ETH df = GetKlines ((symbol=symbol,start=2019-8-11,end=2021-8-11,period=6h) [425]では: df.index = pd.to_datetime ((df.time,unit=ms) [568]: M = 5 # ドンチアン運河の周期容量 pct = 0.003 #追加されたポジションの総ポジションの割合 df[up] = df[high].ローリング ((M).max ((().shift ((1) #upBand ドンチアンチャネル,長いものにするために使用され,tを突破する判断 df[ダウン] = df[].ローリング ((M).max ((().シフト ((1) df[] = (df[]+df[])/2 df[true_range] = pd.concat([df[high]-df[low],df[high]-df[close].shift(1),df[close].shift(1)-df[low]],軸=1).軸=1) df[N] = df[true_range].rolling ((50).mean() #Nは,購入とストップ損失を判断するために使用される最近の変動に等しい. [572]: open_times = 0.3 #ポジション開設の判断 ストップ_タイム = 2.5 #ストップ損失 e = Exchange (([シンボル],料金=0.0004, initial_balance=10000) #取扱者を 0.0004 に設定する res_list = [] last_price = 0 #最後のオープンポジション価格 df.iterrowsの行について: クライン = 列[1] if kline.isnull (().sum (()) > 0: #データなしのセクションをスキップする 続けて ユニット = e.アカウント[USDT][合計]*pct/kline.N #オープンポジション単位金額

if kline.high >  kline.up and e.account[symbol]['amount'] == 0: #first time to open long position 
    e.Buy(symbol,kline.up,unit) #notice the trading price here
    last_price = kline.up
if e.account[symbol]['amount'] > 0 and kline.high > last_price + open_times*kline.N: #long position, buy in 
    e.Buy(symbol,last_price + open_times*kline.N,unit)
    last_price = last_price + open_times*kline.N
if e.account[symbol]['amount'] > 0 and kline.low < last_price - stop_times*kline.N: #long position, stop loss
    e.Sell(symbol,last_price - stop_times*kline.N,e.account[symbol]['amount'])
    
if kline.low <  kline.down and e.account[symbol]['amount'] == 0: #open short
    e.Sell(symbol,kline.down,unit)
    last_price = kline.down
if e.account[symbol]['amount'] < 0 and kline.low < last_price - open_times*kline.N: #short position, buy in 
    e.Sell(symbol,last_price - open_times*kline.N,unit)
    last_price = last_price - open_times*kline.N
if e.account[symbol]['amount'] < 0 and kline.high > last_price + stop_times*kline.N: #short position, stop loss
    e.Buy(symbol,last_price + stop_times*kline.N,-e.account[symbol]['amount'])
    
e.Update({symbol:kline.close})
res_list.append([kline.time, kline.close, e.account[symbol]['amount']*kline.close, e.account['USDT']['total']])

res = pd.DataFrame ((data=res_list, columns=[時間,価格,価値,合計]) res.index = pd.to_datetime (res.time,unit=ms) print(最終市場価値:,res[合計][-1]) 終了[572]:最終市場価値: 280760.566996 [573]: res.total.plot ((figsize=(15,6),グリッド = 真実) 外出[573]:img[571]: (res.value/res.total).plot ((figsize=(15,6),グリッド = 真実) 出場[571]:img

結論

jupyterノートブック研究プラットフォームを使用することに精通している場合は,データ取得,データ分析,戦略バックテスト,チャート表示など,量的な取引への避けられない方法である操作を簡単に実行できます.今,戦略書き方について手がかりがない場合は,まずデータを分析することもできます. 初心者向けに推奨するリソース:

Python を使ってデータ解析を行います.https://wizardforcel.gitbooks.io/pyda-2e/content/

Pythonの定量チュートリアル:https://wizardforcel.gitbooks.io/python-quant-uqer/content/

[ ] で:


もっと