पिछले लेख में, हमने एक एकल व्यापार राशि के एक निश्चित मूल्य से अधिक होने की संभावना के लिए एक अभिव्यक्ति प्राप्त की।
हम समय की अवधि के दौरान व्यापार राशि के वितरण में भी रुचि रखते हैं, जो सहज रूप से व्यक्तिगत व्यापार राशि और आदेश आवृत्ति से संबंधित होना चाहिए। नीचे, हम निश्चित अंतराल में डेटा को संसाधित करते हैं और इसके वितरण को ग्राफ करते हैं, जैसा कि पिछले खंड में किया गया था।
में [1]:
from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
[2] मेंः
trades = pd.read_csv('HOOKUSDT-aggTrades-2023-01-27.csv')
trades['date'] = pd.to_datetime(trades['transact_time'], unit='ms')
trades.index = trades['date']
buy_trades = trades[trades['is_buyer_maker']==False].copy()
buy_trades = buy_trades.groupby('transact_time').agg({
'agg_trade_id': 'last',
'price': 'last',
'quantity': 'sum',
'first_trade_id': 'first',
'last_trade_id': 'last',
'is_buyer_maker': 'last',
'date': 'last',
'transact_time':'last'
})
buy_trades['interval']=buy_trades['transact_time'] - buy_trades['transact_time'].shift()
buy_trades.index = buy_trades['date']
हम किसी भी ट्रेडिंग गतिविधि के बिना अवधि को छोड़कर, 1 सेकंड के अंतराल पर व्यक्तिगत ट्रेड राशि को मिलाकर एकत्रित ट्रेडिंग राशि प्राप्त करते हैं। फिर हम पहले बताए गए एकल ट्रेड राशि विश्लेषण से व्युत्पन्न वितरण का उपयोग करके इस एकत्रित राशि को फिट करते हैं। 1 सेकंड के अंतराल के भीतर प्रत्येक व्यापार को एक एकल व्यापार के रूप में मानते समय परिणाम एक अच्छा फिट दिखाते हैं, प्रभावी रूप से समस्या को हल करते हैं। हालांकि, जब समय अंतराल को ट्रेडिंग आवृत्ति के सापेक्ष बढ़ाया जाता है, तो हम त्रुटियों में वृद्धि का निरीक्षण करते हैं। आगे के शोध से पता चलता है कि यह त्रुटि पैरेटो वितरण द्वारा पेश किए गए सुधार शब्द के कारण होती है। इससे पता चलता है कि जैसे-जैसे समय बढ़ता है और अधिक व्यक्तिगत ट्रेड शामिल होते हैं, कई ट्रेडों का अंतराल संचय पैरेटो वितरण के करीब आता है, जिससे सुधार शब्द को हटाने की आवश्यकता होती है।
[3] मेंः
df_resampled = buy_trades['quantity'].resample('1S').sum()
df_resampled = df_resampled.to_frame(name='quantity')
df_resampled = df_resampled[df_resampled['quantity']>0]
[4] मेंः
# Cumulative distribution in 1s
depths = np.array(range(0, 3000, 5))
probabilities = np.array([np.mean(df_resampled['quantity'] > depth) for depth in depths])
mean = df_resampled['quantity'].mean()
alpha = np.log(np.mean(df_resampled['quantity'] > mean))/np.log(2.05)
probabilities_s = np.array([((1+20**(-depth/mean))*depth/mean+1)**(alpha) for depth in depths])
plt.figure(figsize=(10, 5))
plt.plot(depths, probabilities)
plt.plot(depths, probabilities_s)
plt.xlabel('Depth')
plt.ylabel('Probability of execution')
plt.title('Execution probability at different depths')
plt.grid(True)
बाहर[4]:
[5] मेंः
df_resampled = buy_trades['quantity'].resample('30S').sum()
df_resampled = df_resampled.to_frame(name='quantity')
df_resampled = df_resampled[df_resampled['quantity']>0]
depths = np.array(range(0, 12000, 20))
probabilities = np.array([np.mean(df_resampled['quantity'] > depth) for depth in depths])
mean = df_resampled['quantity'].mean()
alpha = np.log(np.mean(df_resampled['quantity'] > mean))/np.log(2.05)
probabilities_s = np.array([((1+20**(-depth/mean))*depth/mean+1)**(alpha) for depth in depths])
alpha = np.log(np.mean(df_resampled['quantity'] > mean))/np.log(2)
probabilities_s_2 = np.array([(depth/mean+1)**alpha for depth in depths]) # No amendment
plt.figure(figsize=(10, 5))
plt.plot(depths, probabilities,label='Probabilities (True)')
plt.plot(depths, probabilities_s, label='Probabilities (Simulation 1)')
plt.plot(depths, probabilities_s_2, label='Probabilities (Simulation 2)')
plt.xlabel('Depth')
plt.ylabel('Probability of execution')
plt.title('Execution probability at different depths')
plt.legend()
plt.grid(True)
बाहर[5]:
अब विभिन्न समय अवधि के लिए संचित व्यापार राशि के वितरण के लिए एक सामान्य सूत्र का सारांश, प्रत्येक बार अलग से गणना करने के बजाय फिट करने के लिए एकल लेनदेन राशि के वितरण का उपयोग करके। यहाँ सूत्र हैः
यहाँ, avg_interval एकल लेनदेन के औसत अंतराल का प्रतिनिधित्व करता है, और avg_interval_T उस अंतराल के औसत अंतराल का प्रतिनिधित्व करता है जिसका अनुमान लगाया जाना है। यह थोड़ा भ्रमित करने वाला लग सकता है। यदि हम 1 सेकंड के लिए ट्रेडिंग राशि का अनुमान लगाना चाहते हैं, तो हमें 1 सेकंड के भीतर लेनदेन वाले घटनाओं के बीच औसत अंतराल की गणना करने की आवश्यकता है। यदि ऑर्डर की आगमन संभावना पोइसन वितरण का पालन करती है, तो यह सीधे अनुमानित होनी चाहिए। हालांकि, वास्तव में, एक महत्वपूर्ण विचलन है, लेकिन मैं इसे यहां विस्तार से नहीं बताऊंगा।
ध्यान दें कि समय के एक निश्चित अंतराल के भीतर एक विशिष्ट मूल्य से अधिक व्यापार राशि की संभावना और गहराई में उस स्थिति पर व्यापार की वास्तविक संभावना काफी अलग होनी चाहिए। जैसे-जैसे प्रतीक्षा समय बढ़ता है, ऑर्डर बुक में परिवर्तन की संभावना बढ़ जाती है, और व्यापार भी गहराई में परिवर्तन की ओर जाता है। इसलिए, डेटा अपडेट के रूप में वास्तविक समय में एक ही गहराई की स्थिति पर व्यापार की संभावना बदलती है।
[6] मेंः
df_resampled = buy_trades['quantity'].resample('2S').sum()
df_resampled = df_resampled.to_frame(name='quantity')
df_resampled = df_resampled[df_resampled['quantity']>0]
depths = np.array(range(0, 6500, 10))
probabilities = np.array([np.mean(df_resampled['quantity'] > depth) for depth in depths])
mean = buy_trades['quantity'].mean()
adjust = buy_trades['interval'].mean() / 2620
alpha = np.log(np.mean(buy_trades['quantity'] > mean))/0.7178397931503168
probabilities_s = np.array([((1+20**(-depth*adjust/mean))*depth*adjust/mean+1)**(alpha) for depth in depths])
plt.figure(figsize=(10, 5))
plt.plot(depths, probabilities)
plt.plot(depths, probabilities_s)
plt.xlabel('Depth')
plt.ylabel('Probability of execution')
plt.title('Execution probability at different depths')
plt.grid(True)
बाहर[6]:
ट्रेड डेटा मूल्यवान है, और अभी भी बहुत सारे डेटा हैं जिन्हें खनन किया जा सकता है। हमें कीमतों पर ऑर्डर के प्रभाव पर ध्यान देना चाहिए, क्योंकि यह रणनीतियों की स्थिति को प्रभावित करता है। इसी तरह, transact_time के आधार पर डेटा को एकत्र करते हुए, हम अंतिम मूल्य और पहली कीमत के बीच अंतर की गणना करते हैं। यदि केवल एक ऑर्डर है, तो मूल्य अंतर 0 है। दिलचस्प बात यह है कि कुछ डेटा परिणाम नकारात्मक हैं, जो डेटा के क्रम के कारण हो सकते हैं, लेकिन हम यहां इसमें गहराई से नहीं जाएंगे।
परिणामों से पता चलता है कि व्यापारों का अनुपात जो किसी भी प्रभाव का कारण नहीं बनता है वह 77% तक है, जबकि व्यापारों का अनुपात जो 1 टिक के मूल्य आंदोलन का कारण बनता है, 16.5% है, 2 टिक 3.7% है, 3 टिक 1.2% है, और 4 से अधिक टिक 1% से कम है। यह मूल रूप से एक घातीय फ़ंक्शन की विशेषताओं का पालन करता है, लेकिन फिटिंग सटीक नहीं है।
संबंधित मूल्य अंतर का कारण बनने वाली व्यापार राशि का भी विश्लेषण किया गया, जिसमें अत्यधिक प्रभाव के कारण होने वाले विकृतियों को शामिल नहीं किया गया। यह एक रैखिक संबंध दिखाता है, जिसमें प्रत्येक 1000 यूनिट की राशि के कारण लगभग 1 टिक मूल्य उतार-चढ़ाव होता है। इसे ऑर्डर बुक में प्रत्येक मूल्य स्तर के पास रखे गए लगभग 1000 यूनिट के ऑर्डर के औसत के रूप में भी समझा जा सकता है।
[7] मेंः
diff_df = trades[trades['is_buyer_maker']==False].groupby('transact_time')['price'].agg(lambda x: abs(round(x.iloc[-1] - x.iloc[0],3)) if len(x) > 1 else 0)
buy_trades['diff'] = buy_trades['transact_time'].map(diff_df)
[8] मेंः
diff_counts = buy_trades['diff'].value_counts()
diff_counts[diff_counts>10]/diff_counts.sum()
बाहर[8]:
[9] मेंः
diff_group = buy_trades.groupby('diff').agg({
'quantity': 'mean',
'diff': 'last',
})
[10] मेंः
diff_group['quantity'][diff_group['diff']>0][diff_group['diff']<0.01].plot(figsize=(10,5),grid=True);
बाहर[10]:
आइए 2 सेकंड के अंतराल के भीतर मूल्य प्रभाव का विश्लेषण करें। यहाँ अंतर यह है कि नकारात्मक मान हो सकते हैं। हालांकि, चूंकि हम केवल खरीद आदेशों पर विचार कर रहे हैं, इसलिए सममित स्थिति पर प्रभाव एक टिक अधिक होगा। व्यापार राशि और प्रभाव के बीच संबंध का निरीक्षण करना जारी रखते हुए, हम केवल 0 से अधिक परिणामों पर विचार करते हैं। निष्कर्ष एक एकल आदेश के समान है, जो एक अनुमानित रैखिक संबंध दिखाता है, प्रत्येक टिक के लिए लगभग 2000 इकाइयों की मात्रा की आवश्यकता होती है।
[11] मेंः
df_resampled = buy_trades.resample('2S').agg({
'price': ['first', 'last', 'count'],
'quantity': 'sum'
})
df_resampled['price_diff'] = round(df_resampled[('price', 'last')] - df_resampled[('price', 'first')],3)
df_resampled['price_diff'] = df_resampled['price_diff'].fillna(0)
result_df_raw = pd.DataFrame({
'price_diff': df_resampled['price_diff'],
'quantity_sum': df_resampled[('quantity', 'sum')],
'data_count': df_resampled[('price', 'count')]
})
result_df = result_df_raw[result_df_raw['price_diff'] != 0]
[12] मेंः
result_df['price_diff'][abs(result_df['price_diff'])<0.016].value_counts().sort_index().plot.bar(figsize=(10,5));
बाहर[12]:
[23] मेंः
result_df['price_diff'].value_counts()[result_df['price_diff'].value_counts()>30]
बाहर[23]:
[14] मेंः
diff_group = result_df.groupby('price_diff').agg({ 'quantity_sum': 'mean'})
[15] मेंः
diff_group[(diff_group.index>0) & (diff_group.index<0.015)].plot(figsize=(10,5),grid=True);
बाहर[15]:
पहले, हमने एक टिक परिवर्तन के लिए आवश्यक व्यापार राशि निर्धारित की थी, लेकिन यह सटीक नहीं थी क्योंकि यह इस धारणा पर आधारित थी कि प्रभाव पहले ही हुआ था। अब, आइए परिप्रेक्ष्य को उलट दें और व्यापार राशि के कारण होने वाले मूल्य प्रभाव की जांच करें।
इस विश्लेषण में, डेटा को प्रत्येक 1 सेकंड में नमूना किया जाता है, प्रत्येक चरण राशि की 100 इकाइयों का प्रतिनिधित्व करता है। फिर हमने इस राशि सीमा के भीतर मूल्य परिवर्तन की गणना की। यहां कुछ मूल्यवान निष्कर्ष दिए गए हैंः
जहां
[16] मेंः
df_resampled = buy_trades.resample('1S').agg({
'price': ['first', 'last', 'count'],
'quantity': 'sum'
})
df_resampled['price_diff'] = round(df_resampled[('price', 'last')] - df_resampled[('price', 'first')],3)
df_resampled['price_diff'] = df_resampled['price_diff'].fillna(0)
result_df_raw = pd.DataFrame({
'price_diff': df_resampled['price_diff'],
'quantity_sum': df_resampled[('quantity', 'sum')],
'data_count': df_resampled[('price', 'count')]
})
result_df = result_df_raw[result_df_raw['price_diff'] != 0]
[24] मेंः
df = result_df.copy()
bins = np.arange(0, 30000, 100) #
labels = [f'{i}-{i+100-1}' for i in bins[:-1]]
df.loc[:, 'quantity_group'] = pd.cut(df['quantity_sum'], bins=bins, labels=labels)
grouped = df.groupby('quantity_group')['price_diff'].mean()
[25] मेंः
grouped_df = pd.DataFrame(grouped).reset_index()
grouped_df['quantity_group_center'] = grouped_df['quantity_group'].apply(lambda x: (float(x.split('-')[0]) + float(x.split('-')[1])) / 2)
plt.figure(figsize=(10,5))
plt.scatter(grouped_df['quantity_group_center'], grouped_df['price_diff'],s=10)
plt.plot(grouped_df['quantity_group_center'], np.array(grouped_df['quantity_group_center'].values)/2e6-0.000352,color='red')
plt.xlabel('quantity_group_center')
plt.ylabel('average price_diff')
plt.title('Scatter plot of average price_diff by quantity_group')
plt.grid(True)
बाहर[1]:
[19] मेंः
grouped_df.head(10)
बाहर[19]: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
व्यापार राशि के मॉडलिंग और व्यापार राशि के अनुरूप मूल्य प्रभाव के मोटे मॉडल के साथ, इष्टतम ऑर्डर प्लेसमेंट की गणना करना संभव प्रतीत होता है। आइए कुछ धारणाएं बनाएं और एक गैरजिम्मेदार इष्टतम मूल्य स्थिति प्रदान करें।
चलो एक सरल अपेक्षित रिटर्न लिखकर शुरू करते हैं, जो कि 1 सेकंड के भीतर Q से अधिक संचयी खरीद आदेशों की संभावना है, अपेक्षित रिटर्न दर से गुणा (यानी, मूल्य प्रभाव) ।
ग्राफ के आधार पर, अधिकतम अपेक्षित रिटर्न लगभग 2500 है, जो औसत व्यापार राशि का लगभग 2.5 गुना है। इससे पता चलता है कि बिक्री आदेश को 2500 की मूल्य स्थिति पर रखा जाना चाहिए। यह रेखांकित करना महत्वपूर्ण है कि क्षैतिज अक्ष 1 सेकंड के भीतर व्यापार राशि का प्रतिनिधित्व करता है और इसे गहराई स्थिति के बराबर नहीं किया जाना चाहिए। इसके अलावा, यह विश्लेषण ट्रेड डेटा पर आधारित है और इसमें महत्वपूर्ण गहराई डेटा की कमी है।
हमने पाया है कि अलग-अलग समय अंतराल पर व्यापार राशि का वितरण व्यक्तिगत व्यापार राशि के वितरण का एक सरल स्केलिंग है। हमने मूल्य प्रभाव और व्यापार संभावना के आधार पर एक सरल अपेक्षित रिटर्न मॉडल भी विकसित किया है। इस मॉडल के परिणाम हमारी उम्मीदों के अनुरूप हैं, यह दिखाते हुए कि यदि बिक्री आदेश राशि कम है, तो यह मूल्य में कमी का संकेत देता है, और लाभ क्षमता के लिए एक निश्चित राशि की आवश्यकता होती है। व्यापार राशि बढ़ने के साथ संभावना कम हो जाती है, बीच में इष्टतम आकार के साथ, जो इष्टतम आदेश प्लेसमेंट रणनीति का प्रतिनिधित्व करता है। हालांकि, यह मॉडल अभी भी बहुत सरल है। अगले लेख में, मैं इस विषय में गहराई से गहराई से जाऊंगा।
[20] मेंः
# Cumulative distribution in 1s
df_resampled = buy_trades['quantity'].resample('1S').sum()
df_resampled = df_resampled.to_frame(name='quantity')
df_resampled = df_resampled[df_resampled['quantity']>0]
depths = np.array(range(0, 15000, 10))
mean = df_resampled['quantity'].mean()
alpha = np.log(np.mean(df_resampled['quantity'] > mean))/np.log(2.05)
probabilities_s = np.array([((1+20**(-depth/mean))*depth/mean+1)**(alpha) for depth in depths])
profit_s = np.array([depth/2e6-0.000352 for depth in depths])
plt.figure(figsize=(10, 5))
plt.plot(depths, probabilities_s*profit_s)
plt.xlabel('Q')
plt.ylabel('Excpet profit')
plt.grid(True)
बाहर[20]: