私が書いたときビナンス・フューチャーズ・マルチ通貨・ヘッジ戦略に関する研究,私はバックテストエンジンもリリースしました. 最初のレポートは,戦略の有効性を検証した1時間のKラインバックテストに基づいていました. しかし,実際のオープンソース戦略の睡眠時間は
まず,歴史的なK線とは何か.K線データには4つの価格,高,オープン,低,閉,最初の2つの
第"は時間の問題である.K線データの最高価格と最低価格の時刻は与えられていないし,考慮する必要もないが,最も重要な開閉価格は開閉時間ではない.あまり人気のない取引品種でさえ,10秒以上取引しないことが多い.そして,マルチバリエーション戦略をバックテストするとき,開閉価格と閉閉閉価格が同じであると仮定することが多い.これは閉閉価格のバックテストにも基づいている.
2つの品種の仲介をバックテストするために,分数レベルK線を使用することを想像してください. その間の差は通常,10元 (またはドル) です. 10:01時に,契約Aの閉値が100,契約Bは112,差は12元です. したがって,戦略はヘッジを開始します. ある時点で,価格差が戻り,戦略は2元のリターン利益を得ました.
しかし,実際の状況は, 10:00:45 に契約 A が 100 元の取引を行った場合,その後に取引はなく,契約 B は 10:00:58 に 112 元の取引をした場合, 10:01:00 に両価格も存在しない場合である.この時点で市場価格は何で,ヘッジオペレーションはどのくらい得ることができるのか?私は知りません.可能な状況の一つは: 10:00:58 に,契約 A の待機中の注文価格の 101.9
に102.1
戦略の最適化に 大きな誤りをもたらすでしょう
2つ目はマッチメイキング問題です.実際のマッチメイキングは価格優先度と時間優先度です.もし購入者が"販売"価格を超えると,通常は直接"販売"価格で取引します.そうでなければ,待機中のオーダーブックに入力して待機します.Kラインデータには明らかに"購入"と"販売"価格がありません.詳細価格マッチングのレベルをシミュレートすることは不可能です.
最後に,戦略そのものの市場への影響です.少額の資金のバックテストである場合,影響は大きくありません. しかし,取引量が大きい場合,それは市場に影響を及ぼします. 大量の注文をすると価格の滑りが大きくなるだけでなく,長い注文を実行した場合,この種のアクションは実際に購入した他のトレーダーの注文を捕獲します. この効果は定量化できません. 高周波取引は小さな資金しか受け入れられないことを経験からしか言えません.
リアルレベルのバックテストを提供し,実際の歴史的データを得ることができます.20 layer depth price
リアルタイムで2階Ticks
, Each Individual Transaction
FMZはこれらの機能に基づいて リアルタイムトランザクション再生機能を作りました
この種のバックテストデータ量は非常に大きく,バックテスト速度も非常に遅いため,通常は2日間しかバックテストできない.比較的高い頻度または時間的な戦略では,実際の市場レベルのバックテストが必要である.FMZが収集した取引ペアと取引時間は非常に長くないが,依然として7000億以上の歴史的データがある.
現在のマッチメイキングメカニズムは,購入オーダーが
価格深さは偽の深さでもあり得ます しかし,ある種のデータがあります. それは市場の実際の取引意欲です.Each Individual Transaction
この記事では,オーダーフローに基づいた高周波バックテストシステムを提案し,実際の市場レベルのバックテストデータの量を大幅に削減し,ある程度は取引量の市場への影響をシミュレートします.
過去5日間の取引をダウンロードしました (ダウンロードアドレス:https://www.fmz.com/upload/asset/1ff487b007e1a848ead.csv2万3000件の取引データがあります.まず,データの構成を見てみましょう.
[['XTZ', 1590981301905, 2.905, 0.4, 'False\n'],
['XTZ', 1590981303044, 2.903, 3.6, 'True\n'],
['XTZ', 1590981303309, 2.903, 3.7, 'True\n'],
['XTZ', 1590981303738, 2.903, 238.1, 'True\n'],
['XTZ', 1590981303892, 2.904, 0.1, 'False\n'],
['XTZ', 1590981305250, 2.904, 0.1, 'False\n'],
['XTZ', 1590981305643, 2.903, 197.3, 'True\n'],
データとは2次元のリストで,時間順に並べられています. 具体的な意味は以下のとおりです:品種名,取引価格,取引タイムスタンプ,取引量,それが販売注文のアクティブ取引であるかどうか. 買取と販売側があり,各取引には買い手と売り手が含まれます. 買い手は市場である場合.Maker
売り手はアクティブですTaker
最新のデータはTrue
.
まず,取引の方向性により,市場における"1買"と"1売"について,かなり正確に推測することができます.もしアクティブセールオーダーであれば,現時点の"1買"価格は取引価格であり,アクティブセールオーダーであれば",1売"価格は取引価格になります.新しい取引があった場合,すべての価格が更新され,更新されます.更新や更新がない場合,最後の結果は保持されます.上記のデータの最後の瞬間を導入することは簡単です.
注文流量に応じて,次の方法でマッチすることができます: 購入注文を例として,価格price
注文量はamount
1 を買って売る.bid
そしてask
もし,price
より低いask
そしてbid
判断されるのはmaker
取引価格が,取引価格より低かまたは等しいすべての取引が,取引価格が,取引価格よりも低かまたは等しいすべての取引が,取引価格が,取引価格より低かまたは等しいすべての取引が,取引価格より低かまたは等しいすべての取引が,取引価格より低かまたは等しいすべての取引が,取引価格より低かまたは等しいすべての取引が,取引価格より低かまたは等しいすべての取引が,取引価格より低かまたは等しいすべての取引が,取引価格より低かprice
この順序にマッチされます (もしprice
未満または等しいbid
取引価格より低い注文は,取引の優先順位が与えられていない.price
この順番に一致します.)
配当価格はprice
取引の総額である.Each Individual Transaction
オーダーが完全に完了するか,オーダーがキャンセルされるまでask
評価されています.taker
その後に,オーダーが存在している間,すべての取引は,取引価格がprice
この注文と一致し,マッチ価格は取引価格ですEach Individual Transaction
.............maker
そしてtaker
高周波戦略では,この差を考慮する必要があります. 取引先は,取引先の取引額を削減し,取引先の取引額を削減します.
順序が一致している場合は,taker
まず,我々は待機中の注文の量を考慮していない,いくつかのデータがある場合でも,直接取引も価格の深さを変更した判断,市場に影響を与える.
新しい注文のマッチングに基づいて,それは,歴史上の既存の注文をあなたの注文に置き換えることに等しい.いかなる場合でも,それは市場自身の取引量の限界を超えてはならないし,最終利益は市場が生み出す最大利益を超えてはならない.マッチングメカニズムの一部は,注文の量にも影響し,それが戦略の収益に影響を与え,戦略の能力を定量的に反映する.資金の量が倍になり,利益が倍になると,伝統的なバックテストはありません.
注文の購入価格が
交換オブジェクトは,基本的には変化せず,最初の引入を参照することができます.maker
そしてtaker
バックテストの速度を最適化します. 以下は主にマッチングコードを導入します.
symbol = 'XTZ'
loop_time = 0
intervel = 1000 # The sleep time of the strategy is 1000ms
init_price = data[0][2] # Initial price
e = Exchange([symbol],initial_balance=1000000,maker_fee=maker_fee,taker_fee=taker_fee,log='') # Initialize the exchange
depth = {'ask':data[0][2], 'bid':data[0][2]} # depth
order = {'buy':{'price':0,'amount':0,'maker':False,'priority':False,'id':0},
'sell':{'price':0,'amount':0,'maker':False,'priority':False,'id':0}} # order
for tick in data:
price = int(tick[2]/tick_sizes[symbol])*tick_sizes[symbol] # executed price
trade_amount = tick[3] # executed volume
time_stamp = tick[1] # executed timestamp
if tick[4] == 'False\n':
depth['ask'] = price
else:
depth['bid'] = price
if depth['bid'] < order['buy']['price']:
order['buy']['priority'] = True
if depth['ask'] > order['sell']['price']:
order['sell']['priority'] = True
if price > order['buy']['price']:
order['buy']['maker'] = True
if price < order['sell']['price']:
order['sell']['maker'] = True
# Order network delay can also be used as one of the matching conditions, not considered here
cond1 = order['buy']['priority'] and order['buy']['price'] >= price and order['buy']['amount'] > 0
cond2 = not order['buy']['priority'] and order['buy']['price'] > price and order['buy']['amount'] > 0
cond3 = order['sell']['priority'] and order['sell']['price'] <= price and order['sell']['amount'] > 0
cond4 = not order['sell']['priority'] and order['sell']['price'] < price and order['sell']['amount'] > 0
if cond1 or cond2:
buy_price = order['buy']['price'] if order['buy']['maker'] else price
e.Buy(symbol, buy_price, min(order['buy']['amount'],trade_amount), order['buy']['id'], order['buy']['maker'])
order['buy']['amount'] -= min(order['buy']['amount'],trade_amount)
e.Update(time_stamp,[symbol],{symbol:price})
if cond3 or cond4:
sell_price = order['sell']['price'] if order['sell']['maker'] else price
e.Sell(symbol, sell_price, min(order['sell']['amount'],trade_amount), order['sell']['id'], order['sell']['maker'])
order['sell']['amount'] -= min(order['sell']['amount'],trade_amount)
e.Update(time_stamp,[symbol],{symbol:price})
if time_stamp - loop_time > intervel:
order = get_order(e,depth,order) # Trading logic, not given here
loop_time += int((time_stamp - loop_time)/intervel)*intervel
いくつかの詳細を注意してください:
新しい取引が起こると,まず注文をマッチし,次に最新の価格に従って注文します.
各注文には2つの属性があります. メーカーmaker
購入価格が1より大きい場合は,Priority matching
, priority
価格が購入価格に等しいか否かを決定し,メーカーは取引手数料を決定します.
についてmaker
そしてpriority
価格が購入価格より高ければ,残ったボリュームは,市場容量を上回る価格です.maker
.
戦略interval
市場が遅れている可能性があります.
予想された結果を達成できるかどうか確認するために,最も古典的なグリッド戦略の1つをバックテストしましょう. 戦略の原則は,価格が1%上昇するたびに,我々は特定の価値のショートオーダー (逆に,我々はロングオーダー) を保持し,購入オーダーと販売オーダーを事前に計算することです.Grid('XTZ', 100, 0.3, 1000, maker_fee=-0.00002, taker_fee=0.0003)
パラメータは: 取引ペア,価格は,保持値から1%の偏差,待機注文密度は0.3%です, 睡眠間隔ms
,未定の注文料と実行された注文料.
XTZ
まず,異なる保有ポジションが利益収益に与える影響をバックテストします.従来のバックテストメカニズムによってバックテストされた収益は,保有ポジションの増加に比例して確実に増加します.
e1 = Grid('XTZ',100,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e1.account['USDT'])
e2 = Grid('XTZ',1000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e2.account['USDT'])
e3 = Grid('XTZ',10000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e3.account['USDT'])
e4 = Grid('XTZ',100000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e4.account['USDT'])
合計4つのグループがバックテストされ,保有ポジションの値は100,1000,10000,100,000で,バックテストの総時間は1.3秒でした.結果は以下のとおりです.
{'realised_profit': 28.470993031132966, 'margin': 0.7982662957624465, 'unrealised_profit': 0.0104554474048441, 'total': 10000028.481448, 'leverage': 0.0, 'fee': -0.3430967859046398, 'maker_fee': -0.36980249726699727, 'taker_fee': 0.026705711362357405}
{'realised_profit': 275.63148945320177, 'margin': 14.346335829979132, 'unrealised_profit': 4.4382117331794045e-14, 'total': 10000275.631489, 'leverage': 0.0, 'fee': -3.3102045933457784, 'maker_fee': -3.5800688964477048, 'taker_fee': 0.2698643031019274}
{'realised_profit': 2693.8701498889504, 'margin': 67.70120400534114, 'unrealised_profit': 0.5735269329348516, 'total': 10002694.443677, 'leverage': 0.0001, 'fee': -33.984021415250744, 'maker_fee': -34.879233866850974, 'taker_fee': 0.8952124516001403}
{'realised_profit': 22610.231198585603, 'margin': 983.3853688758861, 'unrealised_profit': -20.529965947304365, 'total': 10022589.701233, 'leverage': 0.002, 'fee': -200.87094000385412, 'maker_fee': -261.5849078470078, 'taker_fee': 60.71396784315319}
最終的に実現した利益はそれぞれ保有ポジション価値の28.4%,27.5%,26.9%および22.6%であることが見られる.これは実際の状況にも一致している.保有ポジションの価値が大きいほど,待機中のオーダーの価値が大きいほど,部分取引が起こる可能性が高く,待機中のオーダーの金額に比べて最終的な実現利益が小さい.以下のグラフは,それぞれ100と10000のポジション価値の相対的収益の比較である:
また,待機中の注文密度,睡眠時間,取引手数料など,バックテスト収益に対する異なるパラメータの影響をバックテストすることもできます. නිද眠時間を例として100msに変更し,睡眠時間を1000msに比較して利益の返済を見ることができます.バックテスト結果は以下のとおりです:
{'realised_profit': 29.079440803790423, 'margin': 0.7982662957624695, 'unrealised_profit': 0.0104554474048441, 'total': 10000029.089896, 'leverage': 0.0, 'fee': -0.3703702128662524, 'maker_fee': -0.37938946377435134, 'taker_fee': 0.009019250908098965}
戦略は,注文のセットのみを送信するため,収益が少し増加した,いくつかの注文は,変更する時間がないため,変動する価格を実行することはできません,睡眠時間の削減は,この問題を解決します.これはまた,複数のセットの注文を配置するためのグリッド戦略の重要性を示しています.
この記事では,オーダーフローに基づく新しいバックテストシステムを革新的に提案しており,待機中のオーダー,実行中のオーダー,部分実行されたオーダー,遅延などマッチング状況を部分的にシミュレートすることができ,戦略資金の金額の収益への影響を部分的に反映しています.高周波およびヘジング戦略では,重要な基準値を持っています.高精度バックテストは戦略パラメータ最適化の方向性を示しています.また,長い間検証されています.さらに,バックテストに必要なデータの量はよく制御されており,バックテスト速度も非常に速いです.