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

저자:초목, 창작: 2023-08-09 18:13:16, 업데이트: 2023-09-18 19:51:59

img

이전 기사에서는 다양한 중간 가격 계산 방법을 처음 소개하고 중간 가격의 개정을 제공했으며, 이 글은 이 주제에 대해 더 깊이 연구합니다.

필요한 데이터

주문 흐름 데이터와 열 기구의 깊이 데이터는 실제 디스크에서 수집되며 업데이트 빈도는 100ms입니다. 실제 디스크는 구매/판매 한 장만을 포함하고 있으며 실시간으로 업데이트되며 간결성을 위해 일시적으로 사용되지 않습니다. 데이터가 너무 크기 때문에 10 만 줄의 깊이 데이터만 유지되며 각 기구별 매출도 개별적으로 분리되어 있습니다.

from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import ast
%matplotlib inline
tick_size = 0.0001
trades = pd.read_csv('YGGUSDT_aggTrade.csv',names=['type','event_time', 'agg_trade_id','symbol', 'price', 'quantity', 'first_trade_id', 'last_trade_id',
       'transact_time', 'is_buyer_maker'])
trades = trades.groupby(['transact_time','is_buyer_maker']).agg({
    'transact_time':'last',
    'agg_trade_id': 'last',
    'price': 'first',
    'quantity': 'sum',
    'first_trade_id': 'first',
    'last_trade_id': 'last',
    'is_buyer_maker': 'last',
})
trades.index = pd.to_datetime(trades['transact_time'], unit='ms')
trades.index.rename('time', inplace=True)
trades['interval'] = trades['transact_time'] - trades['transact_time'].shift()
depths = pd.read_csv('YGGUSDT_depth.csv',names=['type','event_time', 'transact_time','symbol', 'u1', 'u2', 'u3', 'bids','asks'])
depths = depths.iloc[:100000]
depths['bids'] = depths['bids'].apply(ast.literal_eval).copy()
depths['asks'] = depths['asks'].apply(ast.literal_eval).copy()
def expand_bid(bid_data):
    expanded = {}
    for j, (price, quantity) in enumerate(bid_data):
        expanded[f'bid_{j}_price'] = float(price)
        expanded[f'bid_{j}_quantity'] = float(quantity)
    return pd.Series(expanded)
def expand_ask(ask_data):
    expanded = {}
    for j, (price, quantity) in enumerate(ask_data):
        expanded[f'ask_{j}_price'] = float(price)
        expanded[f'ask_{j}_quantity'] = float(quantity)
    return pd.Series(expanded)
# 应用到每一行,得到新的df
expanded_df_bid = depths['bids'].apply(expand_bid)
expanded_df_ask = depths['asks'].apply(expand_ask)
# 在原有df上进行扩展
depths = pd.concat([depths, expanded_df_bid, expanded_df_ask], axis=1)
depths.index = pd.to_datetime(depths['transact_time'], unit='ms')
depths.index.rename('time', inplace=True);
trades = trades[trades['transact_time'] < depths['transact_time'].iloc[-1]]

먼저 이 20개 파일 시장의 분포를 살펴보면, 예상대로, 사격 거리가 멀어질수록, 일반적으로 더 많은 청탁이 있으며, 청탁과 판매 청탁은 거의 대칭적입니다.

bid_mean_list = []
ask_mean_list = []
for i in range(20):
    bid_mean_list.append(round(depths[f'bid_{i}_quantity'].mean(),0))
    ask_mean_list.append(round(depths[f'ask_{i}_quantity'].mean(),0))
plt.figure(figsize=(10, 5))
plt.plot(bid_mean_list);
plt.plot(ask_mean_list);
plt.grid(True)

img

깊이 데이터와 거래 데이터를 결합하여 예측의 정확성을 평가하는 것이 편리하다. 여기서 거래 데이터가 깊이 데이터보다 늦게 보장되며, 지연을 고려하지 않고 예측 값과 실제 거래 가격의 평균 오차를 직접 계산하는 것을 보장한다. 예측의 정확성을 측정하는 데 사용됩니다.

결과적으로는, 매입/판매 평균값 mid_price의 오류가 가장 크며, weight_mid_price로 변경한 후, 오류는 즉시 훨씬 작아졌고, 중중값을 조금 더 개선했다. 어제의 기사가 발표된 후, 피드백이 I^3/2로만 확인되어 더 나은 결과를 얻었다. 다음과 같은 이유를 생각해 보았을 때, 사건의 발생 빈도의 차이, I가 -1과 1에 가까운 경우 낮은 확률의 사건으로, 이러한 낮은 확률을 수정하기 위해, 오히려 높은 빈도의 사건의 예측이 더 정확하지 않았으므로, 더 높은 빈도의 사건을 고려하여, 나는 다시 다음과 같은 것을 조정했습니다. (여기는 순수 참조로 시도된 매개 변수이며, 현실은 그다지 중요하지 않습니다):

img

이전 기사에서 언급했듯이 전략은 더 많은 데이터로 예측해야하며, 더 많은 깊이와 주문 거래 데이터와 함께 매각에 얻을 수있는 승리는 이미 약합니다.

df = pd.merge_asof(trades, depths, on='transact_time', direction='backward')
df['spread'] = round(df['ask_0_price'] - df['bid_0_price'],4)
df['mid_price'] = (df['bid_0_price']+ df['ask_0_price']) / 2
df['I'] = (df['bid_0_quantity'] - df['ask_0_quantity']) / (df['bid_0_quantity'] + df['ask_0_quantity'])
df['weight_mid_price'] = df['mid_price'] + df['spread']*df['I']/2
df['adjust_mid_price'] = df['mid_price'] + df['spread']*(df['I'])*(df['I']**8+1)/4
df['adjust_mid_price_2'] = df['mid_price'] + df['spread']*df['I']*(df['I']**2+1)/4
df['adjust_mid_price_3'] = df['mid_price'] + df['spread']*df['I']**3/2
df['adjust_mid_price_4'] = df['mid_price'] + df['spread']*(df['I']+0.3)*(df['I']**4+0.7)/3.8
print('平均值     mid_price的误差:', ((df['price']-df['mid_price'])**2).sum())
print('挂单量加权 mid_price的误差:', ((df['price']-df['weight_mid_price'])**2).sum())
print('调整后的   mid_price的误差:', ((df['price']-df['adjust_mid_price'])**2).sum())
print('调整后的 mid_price_2的误差:', ((df['price']-df['adjust_mid_price_2'])**2).sum())
print('调整后的 mid_price_3的误差:', ((df['price']-df['adjust_mid_price_3'])**2).sum())
print('调整后的 mid_price_4的误差:', ((df['price']-df['adjust_mid_price_4'])**2).sum())
平均值     mid_price的误差: 0.0048751924999999845
挂单量加权 mid_price的误差: 0.0048373440193987035
调整后的   mid_price的误差: 0.004803654771638586
调整后的 mid_price_2的误差: 0.004808216498329721
调整后的 mid_price_3的误差: 0.004794984755260528
调整后的 mid_price_4的误差: 0.0047909595497071375

두 번째 깊이에 대해 생각해보세요.

여기서는 어떤 매개 변수에 영향을 미치는 다른 밸류에이션 범위를 살펴보고, 거래 가격의 변화를 통해 매개 변수의 중간 가격에 대한 기여를 측정하는 아이디어를 사용합니다. 예를 들어, 첫 번째 그림의 깊이는, 거래 가격이 I를 증가하면 거래 가격이 변화할 가능성이 더 높다는 것을 보여줍니다.

두 번째 조는 같은 방식으로 처리되어 효과는 첫 번째 조보다 약간 작지만 무시할 수 없다는 것을 발견했습니다. 세 번째 조의 깊이는 또한 약한 기여를했지만 단조성이 훨씬 나빠졌으며 더 깊은 깊이는 거의 참조 가치가 없습니다.

기여도에 따라 세 가지 차원의 불균형 매개 변수에는 다른 무게가 부여되며, 실제 검사는 다른 계산 방법에 대한 예측 오류가 더 감소합니다.

bins = np.linspace(-1, 1, 50)
df['change'] = (df['price'].pct_change().shift(-1))/tick_size
df['I_bins'] = pd.cut(df['I'], bins, labels=bins[1:])
df['I_2'] = (df['bid_1_quantity'] - df['ask_1_quantity']) / (df['bid_1_quantity'] + df['ask_1_quantity'])
df['I_2_bins'] = pd.cut(df['I_2'], bins, labels=bins[1:])
df['I_3'] = (df['bid_2_quantity'] - df['ask_2_quantity']) / (df['bid_2_quantity'] + df['ask_2_quantity'])
df['I_3_bins'] = pd.cut(df['I_3'], bins, labels=bins[1:])
df['I_4'] = (df['bid_3_quantity'] - df['ask_3_quantity']) / (df['bid_3_quantity'] + df['ask_3_quantity'])
df['I_4_bins'] = pd.cut(df['I_4'], bins, labels=bins[1:])
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(8, 5))


axes[0][0].plot(df.groupby('I_bins')['change'].mean())
axes[0][0].set_title('I')
axes[0][0].grid(True)

axes[0][1].plot(df.groupby('I_2_bins')['change'].mean())
axes[0][1].set_title('I 2')
axes[0][1].grid(True)

axes[1][0].plot(df.groupby('I_3_bins')['change'].mean())
axes[1][0].set_title('I 3')
axes[1][0].grid(True)

axes[1][1].plot(df.groupby('I_4_bins')['change'].mean())
axes[1][1].set_title('I 4')
axes[1][1].grid(True)
plt.tight_layout();

img

df['adjust_mid_price_4'] = df['mid_price'] + df['spread']*(df['I']+0.3)*(df['I']**4+0.7)/3.8
df['adjust_mid_price_5'] = df['mid_price'] + df['spread']*(0.7*df['I']+0.3*df['I_2'])/2
df['adjust_mid_price_6'] = df['mid_price'] + df['spread']*(0.7*df['I']+0.3*df['I_2'])**3/2
df['adjust_mid_price_7'] = df['mid_price'] + df['spread']*(0.7*df['I']+0.3*df['I_2']+0.3)*((0.7*df['I']+0.3*df['I_2'])**4+0.7)/3.8
df['adjust_mid_price_8'] = df['mid_price'] + df['spread']*(0.7*df['I']+0.2*df['I_2']+0.1*df['I_3']+0.3)*((0.7*df['I']+0.3*df['I_2']+0.1*df['I_3'])**4+0.7)/3.8
print('调整后的 mid_price_4的误差:', ((df['price']-df['adjust_mid_price_4'])**2).sum())
print('调整后的 mid_price_5的误差:', ((df['price']-df['adjust_mid_price_5'])**2).sum())
print('调整后的 mid_price_6的误差:', ((df['price']-df['adjust_mid_price_6'])**2).sum())
print('调整后的 mid_price_7的误差:', ((df['price']-df['adjust_mid_price_7'])**2).sum())
print('调整后的 mid_price_8的误差:', ((df['price']-df['adjust_mid_price_8'])**2).sum())
调整后的 mid_price_4的误差: 0.0047909595497071375
调整后的 mid_price_5的误差: 0.0047884350488318714
调整后的 mid_price_6的误差: 0.0047778319053133735
调整后的 mid_price_7的误差: 0.004773578540592192
调整后的 mid_price_8的误差: 0.004771415189297518

거래 데이터를 고려합니다.

거래 데이터는 빈도의 정도를 직접적으로 반영한다. 결국 이것은 실제 금과 은이 참여하는 선택이고, 오프닝 비용은 훨씬 낮으며, 심지어 의도적인 오프닝 속임수도 있다. 따라서 중간 가격을 예측하는 전략은 거래 데이터를 중시해야 한다.

형태를 고려할 때, 정의된 주문의 평균 도착수는 비균형 VI, Vb, Vs는 각각 구매 및 판매 주문의 단위 사건의 평균 수를 나타냅니다.

img

결과는 짧은 시간에 도착하는 숫자가 가격 변화 예측에 가장 중요한 것으로 나타났습니다. VI가 0.1-0.9 사이일 때, 가격과 부정적으로 관련되어 있으며, 범위 밖에서는 가격과 빠르게 긍정적으로 관련되어 있습니다. 이것은 시장이 극심하지 않은 상황에서, 격동이 주를 이루는 경우, 가격이 평형으로 돌아가는 것을 암시합니다. 극심한 시장이 발생하면, 많은 구매 부과 판매 주문이 발생하면, 트렌드를 벗어납니다. 이러한 낮은 확률 상황을 고려하지 않더라도, 단순한 추세와 VI가 부정적인 선형 관계를 만족시키는 것을 가정하면, 중간 가격에 대한 예측 오류 차이는 크게 감소합니다.

img

alpha=0.1
df['avg_buy_interval'] = None
df['avg_sell_interval'] = None
df.loc[df['is_buyer_maker'] == True, 'avg_buy_interval'] = df[df['is_buyer_maker'] == True]['transact_time'].diff().ewm(alpha=alpha).mean()
df.loc[df['is_buyer_maker'] == False, 'avg_sell_interval'] = df[df['is_buyer_maker'] == False]['transact_time'].diff().ewm(alpha=alpha).mean()
df['avg_buy_quantity'] = None
df['avg_sell_quantity'] = None
df.loc[df['is_buyer_maker'] == True, 'avg_buy_quantity'] = df[df['is_buyer_maker'] == True]['quantity'].ewm(alpha=alpha).mean()
df.loc[df['is_buyer_maker'] == False, 'avg_sell_quantity'] = df[df['is_buyer_maker'] == False]['quantity'].ewm(alpha=alpha).mean()
df['avg_buy_quantity'] = df['avg_buy_quantity'].fillna(method='ffill')
df['avg_sell_quantity'] = df['avg_sell_quantity'].fillna(method='ffill')
df['avg_buy_interval'] = df['avg_buy_interval'].fillna(method='ffill')
df['avg_sell_interval'] = df['avg_sell_interval'].fillna(method='ffill')

df['avg_buy_rate'] = 1000 / df['avg_buy_interval']
df['avg_sell_rate'] =1000 / df['avg_sell_interval']

df['avg_buy_volume'] = df['avg_buy_rate']*df['avg_buy_quantity']
df['avg_sell_volume'] = df['avg_sell_rate']*df['avg_sell_quantity']
df['I'] = (df['bid_0_quantity']- df['ask_0_quantity']) / (df['bid_0_quantity'] + df['ask_0_quantity'])
df['OI'] = (df['avg_buy_rate']-df['avg_sell_rate']) / (df['avg_buy_rate'] + df['avg_sell_rate'])
df['QI'] = (df['avg_buy_quantity']-df['avg_sell_quantity']) / (df['avg_buy_quantity'] + df['avg_sell_quantity'])
df['VI'] = (df['avg_buy_volume']-df['avg_sell_volume']) / (df['avg_buy_volume'] + df['avg_sell_volume'])
bins = np.linspace(-1, 1, 50)
df['VI_bins'] = pd.cut(df['VI'], bins, labels=bins[1:])
plt.plot(df.groupby('VI_bins')['change'].mean());
plt.grid(True)

img

df['adjust_mid_price'] = df['mid_price'] + df['spread']*df['I']/2
df['adjust_mid_price_9'] = df['mid_price'] + df['spread']*(-df['OI'])*2
df['adjust_mid_price_10'] = df['mid_price'] + df['spread']*(-df['VI'])*1.4
print('调整后的mid_price   的误差:', ((df['price']-df['adjust_mid_price'])**2).sum())
print('调整后的mid_price_9 的误差:', ((df['price']-df['adjust_mid_price_9'])**2).sum())
print('调整后的mid_price_10的误差:', ((df['price']-df['adjust_mid_price_10'])**2).sum())
调整后的mid_price   的误差: 0.0048373440193987035
调整后的mid_price_9 的误差: 0.004629586542840461
调整后的mid_price_10的误差: 0.004401790287167206

종합 중간 가격

양부량과 거래 데이터가 중간 가격 예측에 도움이 되는 것을 고려하여, 두 가지 매개 변수를 함께 결합하여 무게의 부여가 비교적 임의적이며, 경계 조건도 고려되지 않으며, 극단적인 경우, 예측된 중간 가격은 구매와 판매 사이가 아닐 수도 있지만, 오류가 줄일 수 있는 한, 이러한 세부 사항에 신경쓰지 않을 수도 있습니다.

마지막 예측의 오류는 0.00487에서 0.0043로 떨어졌습니다. 여기까지 더 깊이 들어가지 않습니다. 중간 가격은 채굴 할 수있는 것이 많습니다.

#注意VI需要延后一个使用
df['price_change'] = np.log(df['price']/df['price'].rolling(40).mean())
df['CI'] = -1.5*df['VI'].shift()+0.7*(0.7*df['I']+0.2*df['I_2']+0.1*df['I_3'])**3 + 150*df['price_change'].shift(1)
df['adjust_mid_price_11'] = df['mid_price'] + df['spread']*(df['CI'])
print('调整后的mid_price_11的误差:', ((df['price']-df['adjust_mid_price_11'])**2).sum())
调整后的mid_price_11的误差: 0.00421125960463469

요약

이 문서는 깊이 데이터와 거래 데이터와 결합하여 중간 가격의 계산 방법을 더욱 개선하고, 정확성을 측정하는 방법을 제시하여 가격 변화 예측의 정확성을 향상시킵니다. 전체적으로 다양한 매개 변수는 너무 엄격하지 않으며, 참조를 위해만 사용됩니다. 보다 정확한 중간 가격이 있으며, 실제 응용 중간 가격이 다시 측정됩니다. 이 부분에는 많은 내용이 있습니다.


더 많은

mztcoin

루이스누가 알아?

키티고귀한 자와 빈자,