고주파 거래 전략에 대한 생각 (2)

저자:리디아, 창작: 2023-08-04 17:17:30, 업데이트: 2023-09-12 15:50:31

img

고주파 거래 전략에 대한 생각 (2)

누적 거래액 모델링

이전 기사에서, 우리는 단일 거래 금액이 특정 값보다 크다는 확률을 나타내는 표현식을 도출했습니다.

img

우리는 또한 시간 기간에 거래 금액의 분포에 관심이 있습니다. 이는 직관적으로 개별 거래 금액과 주문 빈도에 관련이 있어야합니다. 아래에서 우리는 일정한 간격으로 데이터를 처리하고 이전 섹션에서 수행 된 것과 유사한 분포를 그래프합니다.

[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]:

img

[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]:

img

이제 각 시간에 별도로 계산하기 보다는, 적합 하 게 단일 거래 금액의 분포를 사용하여, 다른 시간 기간에 축적 된 거래 금액의 분배를 위한 일반적인 공식을 요약합니다. 여기 공식을 있습니다:

img

여기서, 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]:

img

단일 무역 가격 영향

트레이드 데이터는 가치가 있고, 여전히 많은 데이터가 채굴될 수 있습니다. 이것은 전략의 위치에 영향을 미치기 때문에 가격에 대한 주문의 영향에 주의를 기울여야 합니다. 마찬가지로, 트랜잭션_타임에 기반한 데이터를 집계하면 마지막 가격과 첫 번째 가격 사이의 차이를 계산합니다. 하나의 주문만 있으면 가격 차이가 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]:

img

[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]:

img

고정 기간 가격 영향

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]:

img

[23]에서:

result_df['price_diff'].value_counts()[result_df['price_diff'].value_counts()>30]

아웃[23]:

img

[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]:

img

무역액의 가격 영향

이전에는 틱 변경에 필요한 거래 금액을 결정했지만 이미 영향을 받았다는 가정에 기초했기 때문에 정확하지 않았습니다. 이제 관점을 뒤집어 거래 금액으로 인한 가격 영향을 살펴 보겠습니다.

이 분석에서, 데이터는 1초마다 샘플링되며, 각 단계는 100개의 유닛을 나타냅니다. 그 다음 우리는 이 유닛 범위 내에서 가격 변화를 계산했습니다. 여기 몇 가지 가치있는 결론이 있습니다:

  1. 구매 주문 금액이 500보다 낮을 때 예상되는 가격 변화는 감소합니다. 또한 가격에 영향을 미치는 판매 주문이 있기 때문에 예상되는 것입니다.
  2. 거래 금액이 낮을 때 선형적인 관계가 존재하며, 거래 금액이 클수록 가격 상승이 더 크다는 것을 의미합니다.
  3. 구매 주문 금액이 증가함에 따라 가격 변화는 더 중요해집니다. 이것은 종종 가격 돌파를 나타냅니다. 추가로 고정 간격 샘플링은 데이터 불안정을 증가시킵니다.
  4. 스커터 그래프의 상단에 주의를 기울이는 것이 중요합니다. 이는 거래 금액과 함께 가격 증가와 일치합니다.
  5. 이 특정 거래 쌍을 위해, 우리는 거래 금액과 가격 변화 사이의 관계의 대략적인 버전을 제공합니다.

img

여기서 C는 가격의 변화를 나타내고 Q는 구매 주문의 양을 나타냅니다.

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

외출[25]:

img

[19]에서:

grouped_df.head(10)

아웃[19]: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

img

초기 최적 주문 배치

거래 금액의 모델링과 거래 금액에 대응하는 가격 영향의 대략적인 모델로 최적의 주문 배치를 계산하는 것이 가능해 보입니다. 몇 가지 가정을 하고 무책임한 최적의 가격 위치를 제공합니다.

  1. 영향을 받은 후에 가격이 원래 값으로 되돌아간다고 가정합니다. (이것은 거의 가능하지 않으며 영향을 받은 후 가격 변화에 대한 추가 분석이 필요합니다.)
  2. 이 기간 동안 거래 금액과 주문 빈도의 분포가 미리 설정된 패턴을 따르고 있다고 가정합니다 (이것은 또한 정확하지 않습니다. 우리는 하루 데이터에 기초하여 추정하고 거래는 명확한 클러스터링 현상을 보여줍니다).
  3. 시뮬레이션 기간 동안 단 하나의 판매 주문이 발생하고 닫힌다고 가정합니다.
  4. 주문이 실행된 후, 특히 금액이 매우 낮을 때 가격을 계속 끌어올리는 다른 구매 주문이 있다고 가정합니다. 이 효과는 여기서 무시되며 가격이 퇴보 할 것이라고 가정합니다.

간단한 예상 수익을 작성하는 것으로 시작해 보겠습니다. 이는 1초 이내에 Q를 초과하는 누적 구매 주문의 확률이고, 예상 수익률 (즉 가격 영향) 으로 곱합니다.

img

그래프에 따르면 최대 기대 수익률은 평균 거래 금액의 약 2.5배인 약 2500입니다. 이것은 판매 주문이 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]:

img


더 많은