Tư duy về chiến lược giao dịch tần số cao (2)

Tác giả:Cỏ nhỏ, Tạo: 2023-08-04 16:14:27, Cập nhật: 2023-09-19 09:08:17

img

Bài viết chủ yếu đề cập đến chiến lược giao dịch tần số cao, nghiên cứu tập trung vào mô hình hóa giao dịch tích lũy và cú sốc giá. Bài viết đưa ra một mô hình đầu tiên về vị trí giao dịch ưu việt nhất bằng cách phân tích các giao dịch đơn lẻ, cú sốc giá ở khoảng cách cố định và ảnh hưởng của giao dịch đối với giá. Mô hình này dựa trên sự hiểu biết về khối lượng giao dịch và cú sốc giá, cố gắng tìm vị trí giao dịch tối ưu nhất.

Mô hình hóa giao dịch tích lũy

Bài trước đưa ra một biểu thức xác suất giao dịch đơn lớn hơn một giá trị:

img

Chúng ta cũng quan tâm đến sự phân bố khối lượng giao dịch trong một khoảng thời gian, và trực quan, nó nên liên quan đến số lượng giao dịch và tần suất đặt hàng mỗi lần. Dưới đây, xử lý dữ liệu theo khoảng thời gian cố định.

from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
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']

Kết hợp các giao dịch đơn lẻ với mỗi khoảng thời gian 1s thành số giao dịch, loại bỏ phần không giao dịch, và kết hợp với phân bố giao dịch đơn lẻ trên, kết quả có thể thấy tốt hơn, xem tất cả các giao dịch trong 1s là một đơn lẻ, vấn đề này đã trở thành một vấn đề đã được giải quyết. Nhưng khi chu kỳ kéo dài (so với tần suất giao dịch), sai số được tìm thấy tăng lên, và nghiên cứu cho thấy sai số này chính xác là do sửa đổi phân bố Pareto trước đó. Điều này cho thấy khi chu kỳ kéo dài, chứa nhiều giao dịch đơn lẻ hơn, nhiều giao dịch kết hợp gần với phân bố Pareto tích lũy hơn, tình huống này cần loại bỏ sửa đổi.

df_resampled = buy_trades['quantity'].resample('1S').sum()
df_resampled = df_resampled.to_frame(name='quantity')
df_resampled = df_resampled[df_resampled['quantity']>0]
buy_trades
agg_trade_id giá cả số lượng first_trade_id Last_trade_id là_buyer_maker ngày Transact_time khoảng thời gian khác nhau
2023-01-27 00:00:00.161 1138369 2.901 54.3 3806199 3806201 Không đúng 2023-01-27 00:00:00.161 1674777600161 N/A 0.001
2023-01-27 00:00:04.140 1138370 2.901 291.3 3806202 3806203 Không đúng 2023-01-27 00:00:04.140 1674777604140 3979.0 0.000
2023-01-27 00:00:04.339 1138373 2.902 55.1 3806205 3806207 Không đúng 2023-01-27 00:00:04.339 1674777604339 199.0 0.001
2023-01-27 00:00:04.772 1138374 2.902 1032.7 3806208 3806223 Không đúng 2023-01-27 00:00:04.772 1674777604772 433.0 0.000
2023-01-27 00:00:05.562 1138375 2.901 3.5 3806224 3806224 Không đúng 2023-01-27 00:00:05.562 1674777605562 790.0 0.000
2023-01-27 23:59:57.739 1544370 3.572 394.8 5074645 5074651 Không đúng 2023-01-27 23:59:57.739 1674863997739 1224.0 0.002
2023-01-27 23:59:57.902 1544372 3.573 177.6 5074652 5074655 Không đúng 2023-01-27 23:59:57.902 1674863997902 163.0 0.001
2023-01-27 23:59:58.107 1544373 3.573 139.8 5074656 5074656 Không đúng 2023-01-27 23:59:58.107 1674863998107 205.0 0.000
2023-01-27 23:59:58.302 1544374 3.573 60.5 5074657 5074657 Không đúng 2023-01-27 23:59:58.302 1674863998302 195.0 0.000
2023-01-27 23:59:59.894 1544376 3.571 12.1 5074662 5074664 Không đúng 2023-01-27 23:59:59.894 1674863999894 1592.0 0.000
#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)

png

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]) # 无修正

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)

png

Bây giờ để tổng hợp một công thức chung cho phân bố các giao dịch tích lũy theo thời gian khác nhau, hãy sử dụng phân bố giao dịch đơn lẻ để phù hợp, mà không cần phân tích riêng biệt mỗi lần.

img

Trong đó avg_interval chỉ khoảng cách trung bình của giao dịch đơn lẻ và avg_interval_T chỉ khoảng cách trung bình cần ước tính, nói một chút đi vòng qua. Nếu chúng ta ước tính giao dịch 1s, cần thống kê khoảng cách trung bình của các sự kiện được giao dịch trong 1s. Nếu xác suất đến của đơn hàng phù hợp với phân bố Parsons, nó nên có thể được ước tính trực tiếp ở đây, nhưng độ lệch thực tế rất lớn, không được giải thích ở đây.

Lưu ý rằng xác suất giao dịch lớn hơn một giá trị cụ thể trong khoảng thời gian nào đó ở đây và xác suất giao dịch thực tế ở vị trí đó trong độ sâu nên khác nhau lớn hơn, vì thời gian chờ lâu hơn, khả năng thay đổi sổ hàng sẽ cao hơn và giao dịch cũng dẫn đến sự thay đổi độ sâu, do đó xác suất giao dịch ở cùng một vị trí độ sâu thay đổi trong thời gian thực khi dữ liệu được cập nhật.

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)

png

Đánh giá giao dịch đơn lẻ

Dữ liệu giao dịch là một kho báu, và có rất nhiều dữ liệu để khai thác. Chúng ta nên rất chú ý đến tác động của đơn đặt hàng lên giá cả, ảnh hưởng đến vị trí đặt hàng của chiến lược. Cũng dựa trên dữ liệu tổng hợp transact_time, tính toán chênh lệch giữa giá cuối cùng và giá đầu tiên, nếu chỉ có một đơn đặt hàng, chênh lệch là 0. Điều lạ là vẫn có một số lượng nhỏ dữ liệu kết quả âm, nên là vấn đề thứ tự dữ liệu, không đi sâu ở đây.

Kết quả cho thấy tỷ lệ không gây ra cú sốc lên đến 77%, tỷ lệ một dấu chấm là 16.5%, hai dấu chấm là 3.7%, ba dấu chấm là 1.2, và bốn dấu chấm trở lên là dưới 1%.

Số lượng giao dịch gây ra chênh lệch giá tương ứng đã được thống kê, loại bỏ sự sai lệch quá lớn của cú sốc, cơ bản là phù hợp với mối quan hệ tuyến tính, khoảng 1.000 số lượng gây ra sự biến động giá 1 tick. Nó cũng có thể được hiểu là trung bình khoảng 1.000 đơn vị đeo giá gần mỗi đĩa.

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)
diff_counts = buy_trades['diff'].value_counts()
diff_counts[diff_counts>10]/diff_counts.sum()
0.000    0.769965
0.001    0.165527
0.002    0.037826
0.003    0.012546
0.004    0.005986
0.005    0.003173
0.006    0.001964
0.007    0.001036
0.008    0.000795
0.009    0.000474
0.010    0.000227
0.011    0.000187
0.012    0.000087
0.013    0.000080
Name: diff, dtype: float64
diff_group = buy_trades.groupby('diff').agg({
    'quantity': 'mean',
    'diff': 'last',
})
diff_group['quantity'][diff_group['diff']>0][diff_group['diff']<0.01].plot(figsize=(10,5),grid=True);

png

Động thái giá định kỳ

Giá đột phá trong thống kê 2s, khác biệt là ở đây sẽ có âm tính, tất nhiên vì chỉ thống kê thanh toán ở đây, vị trí đối xứng sẽ lớn hơn một dấu chấm. Tiếp tục quan sát mối quan hệ giao dịch và đột phá, chỉ kết quả thống kê lớn hơn 0, kết luận và đơn đặt hàng gần như, cũng là mối quan hệ tuyến tính gần như, mỗi dấu chấm cần khoảng 2000 số lượng.

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]
result_df['price_diff'][abs(result_df['price_diff'])<0.016].value_counts().sort_index().plot.bar(figsize=(10,5));

png

result_df['price_diff'].value_counts()[result_df['price_diff'].value_counts()>30]
 0.001    7176
-0.001    3665
 0.002    3069
-0.002    1536
 0.003    1260
 0.004     692
-0.003     608
 0.005     391
-0.004     322
 0.006     259
-0.005     192
 0.007     146
-0.006     112
 0.008      82
 0.009      75
-0.007      75
-0.008      65
 0.010      51
 0.011      41
-0.010      31
Name: price_diff, dtype: int64
diff_group = result_df.groupby('price_diff').agg({ 'quantity_sum': 'mean'})
diff_group[(diff_group.index>0) & (diff_group.index<0.015)].plot(figsize=(10,5),grid=True);

png

Động thái giá trị giao dịch

Trước đây tìm kiếm một giao dịch cần thay đổi tick, nhưng không chính xác, vì nó được xây dựng trong trường hợp giả định cú sốc đã xảy ra. Bây giờ ngược lại, xem cú sốc giá mà giao dịch hoàn thành.

Ở đây, dữ liệu được lấy mẫu theo 1s, một bước dài trên 100 đơn vị, và thống kê sự thay đổi giá trong phạm vi số lượng này.

  1. Khi giao dịch giao dịch dưới 500, thay đổi giá mong đợi là giảm, điều này phù hợp với mong đợi, sau khi tất cả các đơn đặt hàng bán cũng ảnh hưởng đến giá.
  2. Trong khi giao dịch thấp, phù hợp với mối quan hệ tuyến tính, tức là giao dịch lớn hơn, giá tăng lớn hơn.
  3. Số lượng giao dịch lớn hơn, mức độ thay đổi giá lớn hơn, thường đại diện cho sự đột phá của giá, giá có thể quay trở lại sau khi đột phá, cùng với việc lấy mẫu ở khoảng cách cố định, gây ra sự không ổn định của dữ liệu.
  4. Cần chú ý đến phần trên cùng của biểu đồ phân đoạn, đó là phần giao dịch tương ứng với giá tăng.
  5. Chỉ cho cặp giao dịch này, hãy cho chúng ta một mối quan hệ giữa khối lượng giao dịch và sự thay đổi giá cả:

img

Trong đó, C cho thấy sự thay đổi về giá, Q cho thấy số lượng giao dịch được giao dịch.

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]
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()
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)

png

grouped_df.head(10)
số lượng_nhóm price_diff quantity_group_center
0 0-199 -0.000302 99.5
1 100-299 -0.000124 199.5
2 200-399 -0.000068 299.5
3 300-499 -0.000017 399.5
4 400-599 -0.000048 499.5
5 500-699 0.000098 599.5
6 600-799 0.000006 699.5
7 700-899 0.000261 799.5
8 800-999 0.000186 899.5
9 900-1099 0.000299 999.5

Địa điểm ưu tiên ban đầu

Với mô hình hóa khối lượng giao dịch và mô hình thô của khối lượng giao dịch tương ứng với cú sốc giá, có vẻ như bạn có thể tính ra vị trí xếp hạng tối ưu.

  1. Giả sử giá trở lại mức nguyên thủy sau cú sốc (thật không chắc chắn, cần phân tích lại sự thay đổi giá sau cú sốc)
  2. Giả sử phân bố khối lượng giao dịch và tần suất đặt hàng trong thời gian này phù hợp với dự đoán (đây cũng không chính xác, đây là ước tính với giá trị trong ngày, trong khi giao dịch có sự tập hợp rõ ràng).
  3. Giả sử chỉ có một giao dịch bán trong thời gian mô phỏng, sau đó ngang hàng.
  4. Giả sử sau khi giao dịch được thực hiện, các khoản thanh toán khác tiếp tục thúc đẩy giá tăng, đặc biệt là khi số lượng rất thấp, hiệu ứng này bị bỏ qua ở đây, đơn giản là sẽ trở lại.

Bắt đầu bằng cách viết một lợi nhuận mong đợi đơn giản, đó là xác suất thanh toán tích lũy lớn hơn Q trong 1s, nhân với tỷ lệ lợi nhuận mong đợi (tức là giá của cú sốc):

img

Theo hình ảnh, lợi nhuận mong đợi lớn nhất là khoảng 2500 và khoảng 2,5 lần số lượng giao dịch trung bình. Điều này có nghĩa là đơn bán nên được treo ở vị trí 2500. Một lần nữa cần nhấn mạnh rằng khối lượng giao dịch trong trục ngang đại diện cho 1s không thể đơn giản là tương đương với vị trí sâu.

Tóm lại

Phát hiện ra rằng phân bố giao dịch giữa các khoảng thời gian khác nhau là một sự mở rộng đơn giản về phân bố giao dịch đơn lẻ. Cũng dựa trên cú sốc giá và xác suất giao dịch, một mô hình thu nhập mong đợi đơn giản đã được thực hiện, kết quả của mô hình này phù hợp với mong đợi của chúng tôi, nếu số lượng giao dịch bán nhỏ, báo trước giá giảm, cần một lượng nhất định để có khoảng cách lợi nhuận, và khối lượng giao dịch lớn hơn thì xác suất thấp hơn, có một kích thước tối ưu ở giữa, cũng là vị trí chiến lược tìm kiếm.

#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)

png


Thêm nữa

Phân tích 🐂🍺