Pensamiento sobre estrategias de trading de alta frecuencia (5)

El autor:Las hierbas, Creado: 2023-08-09 18:13:16, Actualizado: 2023-09-18 19:51:59

img

El artículo anterior introdujo inicialmente varios métodos de cálculo de precios intermedios y dio una revisión de los precios intermedios, que este artículo continúa profundizando en el tema.

Datos requeridos

Los datos de flujo de pedidos y los datos de profundidad de diez discos, provienen de la recopilación de discos reales, y la frecuencia de actualización es de 100 ms. Los discos reales solo contienen datos de compra y venta de un solo disco y se actualizan en tiempo real, por razones de brevedad, no son útiles temporalmente.

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

En primer lugar, veamos la distribución de los 20 archivos del mercado, de acuerdo con las expectativas, la distancia entre los registros, generalmente hay más registros, y los registros de compra y venta son más o menos simétricos.

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

La combinación de datos de profundidad y datos de transacción facilita la evaluación de la precisión de las predicciones. Aquí se garantiza que los datos de transacción son posteriores a los datos de profundidad y se calcula directamente el valor de la predicción con el error medio del precio de transacción real sin tener en cuenta el tiempo de espera.

De acuerdo con los resultados, el error de medio_precio de compra y venta es el mayor, y después de cambiar a weight_mid_price, el error se redujo inmediatamente mucho, mejorando un poco más con el ajuste del precio medio ponderado. Después de la publicación del artículo de ayer, hubo comentarios que solo usaron I^3/2, y aquí lo revisaron y encontraron mejores resultados. Pensando en la siguiente razón, debería ser la diferencia en la frecuencia de los eventos, I es un evento de baja probabilidad cuando está cerca de -1 y 1, para corregir estas bajas probabilidades, en cambio, el pronóstico de eventos de alta frecuencia no es tan preciso, por lo tanto, en el caso de eventos de alta frecuencia, he ajustado lo siguiente:

img

Los resultados son ligeramente mejores. El artículo anterior dijo que la estrategia debería hacer predicciones con más datos, y que la mejora obtenida por el entrelazamiento y la venta es débil con más profundidad y datos de transacción de pedidos.

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

Considere la profundidad de segundo grado.

En este caso, la idea es examinar el rango de variación de un parámetro que influye en el valor de la transacción para medir la contribución de este parámetro al precio intermedio. Por ejemplo, en el gráfico de profundidad de primer grado, con el aumento de I, el precio de la transacción es más probable que el precio de la transacción cambie en la dirección correcta, lo que indica que I ha hecho una contribución positiva.

El segundo disco fue tratado de la misma manera, y se encontró que aunque el efecto es un poco menor que el primer disco, no se puede ignorar. La profundidad del tercer disco también contribuyó de forma débil, pero la monotonía fue mucho peor, y la profundidad más profunda no tenía casi ningún valor de referencia.

Dependiendo del grado de contribución, los parámetros de desequilibrio de los tres grados se asignan diferentes pesos, y la corrección real para los diferentes métodos de cálculo reduce aún más el error de predicción.

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

Considere los datos de transacción

Los datos de transacción reflejan directamente el grado de espacio, después de todo, esta es la opción de la participación de oro y plata reales, mientras que el costo de los anuncios es mucho más bajo, e incluso hay casos de engaño intencional de anuncios. Por lo tanto, la estrategia de previsión de precios intermedios debe centrarse en los datos de transacción.

Teniendo en cuenta la forma, se define el número de pedidos de media llegada no equilibrada VI, Vb, Vs representan respectivamente el número promedio en los eventos unitarios de pedidos y pedidos de venta.

img

Los resultados muestran que el número de llegadas en el corto plazo es más significativo en las predicciones de cambios en los precios, cuando VI está entre < 0.1-0.9 y correlacionado con los precios negativos, mientras que fuera del rango, se correlaciona rápidamente con los precios positivos. Esto sugiere que los precios regresan a la estabilidad cuando el mercado no es extremo, dominado por la conmoción, y cuando el mercado extremo se presenta, como un gran número de pedidos sobrevendidos, cuando se sale de la tendencia. Incluso sin tener en cuenta estas situaciones de baja probabilidad, el simple supuesto de que la tendencia y VI satisfagan una relación lineal negativa, la diferencia de error de la predicción del precio intermedio disminuye significativamente.

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

Precio intermedio combinado

Dado que tanto el volumen de pedidos como los datos de transacciones son útiles para predecir el precio intermedio, se pueden combinar los dos parámetros, donde la asignación de peso es bastante arbitraria y no se tienen en cuenta las condiciones de la frontera. En casos extremos, el precio intermedio de la predicción puede no estar entre el buy one y el sell one, pero siempre que el error pueda reducirse, no se preocupan por estos detalles.

El error del pronóstico final se redujo de 0.00487 al principio a 0.0043, no podemos profundizar más, el precio intermedio tiene mucho que extraer, después de todo, el precio intermedio es el precio del pronóstico, todos pueden probarlo por sí mismos.

#注意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

Resumen

Este artículo combina datos profundos y datos de transacciones, mejora aún más el método de cálculo del precio intermedio, proporciona un método para medir la precisión y mejora la precisión de las predicciones de cambios de precios. En general, los parámetros son menos rigurosos, solo para referencia. Hay precios intermedios más precisos, luego se vuelve a evaluar el precio intermedio de aplicación real.


Más.

el mztcoinLas vacas se quedaron sin hierba y esperan la próxima actualización

- ¿ Por qué?¿Quién lo entiende?

¿Qué quieres decir?No hay que admirar a las mujeres que no están casadas.