
Estoy aquíEstrategia de cobertura multidivisa de Binance: posiciones cortas, sobre subidas, posiciones largas y sobre caídasTambién se lanzó al mismo tiempo un motor de backtesting. El primer informe verificó la efectividad de la estrategia basándose en un backtest de línea K de una hora. Sin embargo, el tiempo de inactividad real de la estrategia pública es de 1 s, lo que es una estrategia de frecuencia muy alta. Obviamente, es imposible obtener resultados precisos mediante pruebas retrospectivas con la línea K horaria. Posteriormente se añadióPrueba retrospectiva de la línea de minutosComo resultado, las ganancias del backtesting han aumentado mucho, pero aún es imposible determinar qué parámetros deben usarse en la situación de segundo nivel y la comprensión de toda la estrategia no es muy clara. La razón principal es la importante desventaja del backtesting basado en la línea K.
En primer lugar, ¿qué es la línea K histórica? Los datos de una línea K incluyen cuatro precios: máximo de apertura y mínimo de cierre, dos horas de inicio y un volumen de negociación de rango. La mayoría de las plataformas y marcos cuantitativos se basan en pruebas retrospectivas de línea K, y la plataforma cuantitativa FMZ también proporciona pruebas retrospectivas a nivel de tick. El backtesting de la línea K es muy rápido y no hay problemas en la mayoría de los casos, pero también tiene fallas muy graves, especialmente cuando se realizan backtesting de estrategias de múltiples variedades y estrategias de alta frecuencia, es casi imposible sacar conclusiones correctas.
El primero es el tema del tiempo. No se indica el momento de los precios más altos y más bajos de los datos de la línea K, por lo que no es necesario considerarlo. Pero los precios de apertura y cierre más importantes no comienzan desde los precios de apertura y cierre. Hora de cierre. Incluso en el caso de los productos de trading menos populares, a menudo no se realiza ninguna operación durante más de diez segundos. Cuando realizamos pruebas retrospectivas de estrategias multiproducto, a menudo asumimos que sus precios de apertura y cierre son simultáneos. Esta es también la base para realizar pruebas retrospectivas del precio de cierre.
Imaginemos que utilizamos la línea de minutos para hacer una prueba retrospectiva del arbitraje de dos variedades. Su diferencia de precio suele ser de 10 yuanes. Ahora se descubre que a las 10:01, el precio de cierre del contrato A es de 100 y el del contrato B es de 112. La diferencia de precio Son 12 yuanes. Por lo tanto, la estrategia comienza a cubrirse. En ese momento, la diferencia de precio volvió y la estrategia obtuvo una ganancia de retorno de 2 yuanes.
La situación real puede ser que a las 10:00:45, el contrato A generó una transacción de 100 yuanes y no hubo ninguna transacción a partir de entonces. A las 10:00:58, el contrato B generó una transacción de 112 yuanes. A las 10:01, Ambos precios no existen, ¿cuál es el precio del mercado en este momento y cuánta diferencia de precio se puede obtener con la cobertura? No hay forma de saberlo. Un escenario posible es: a las 10:00:58, el precio de oferta y demanda del contrato A es 101,9-102,1, y no hay ninguna diferencia de precio de 2 yuanes. Esto confundirá enormemente nuestra estrategia de optimización.
La segunda cuestión es la correspondencia. La correspondencia real prioriza el precio y el tiempo. Si el comprador supera el precio de venta, la transacción generalmente se completará directamente al precio de venta. De lo contrario, ingresará al libro de órdenes y esperará. Los datos de la línea K obviamente no tienen un precio de compra y venta, y es imposible simular la correspondencia a nivel detallado.
Por último, está el impacto de la propia estrategia en el mercado. Si se trata de un backtest de capital pequeño, el impacto no será significativo. Pero si el volumen de operaciones representa una gran proporción, tendrá un impacto en el mercado. No solo el deslizamiento de precios será grande cuando la transacción se ejecuta inmediatamente, sino que si su orden de compra se ejecuta a través de pruebas retrospectivas, en realidad anticipará las transacciones de otros comerciantes que originalmente querían comprar, y el efecto mariposa tendrá un impacto en el mercado. Este impacto no se puede cuantificar y solo podemos decir, con base en la experiencia, que el trading de alta frecuencia solo puede dar cabida a fondos pequeños.
FMZ proporciona pruebas retrospectivas en tiempo real, que pueden obtener una profundidad histórica real de 20 niveles, ticks de segundo nivel en tiempo real, datos transacción por transacción y, en base a esto,Función de reproducción en tiempo real. La cantidad de datos de backtesting es extremadamente grande y la velocidad es muy lenta, normalmente sólo dos días. Para estrategias de frecuencia relativamente alta o estrategias que requieren un juicio temporal estricto, es necesario realizar pruebas retrospectivas en tiempo real. Los pares de transacciones y los períodos de tiempo recopilados por FMZ no son largos, pero hay más de 70 mil millones de datos históricos. El mecanismo de coincidencia actual es que si la orden de compra es mayor que la orden de venta, se igualará totalmente de inmediato, independientemente del volumen; si es menor que la orden de venta, ingresará a la cola de coincidencia. Este mecanismo de backtesting resuelve los dos primeros problemas del backtesting de la línea K, pero todavía no puede resolver el último problema. Y debido a que la cantidad de datos es tan grande, la velocidad y el rango de tiempo de las pruebas retrospectivas son limitados.

Hay muy poca información de la línea K y la profundidad puede ser falsa, pero hay un tipo de datos que reflejan la verdadera intención de transacción del mercado y reflejan el historial de transacciones más auténtico, es decir, transacción por transacción. Este artículo propondrá un sistema de backtesting de alta frecuencia basado en el flujo de órdenes, que reducirá en gran medida la cantidad de datos para el backtesting en tiempo real y simulará el impacto del volumen de negociación en el mercado hasta cierto punto.
Descargué los registros de transacciones del contrato perpetuo de Binance XTZ en los últimos 5 días (dirección de descarga: https://www.fmz.com/upload/asset/1ff487b007e1a848ead.csv). Como no es un producto muy popular, hay 213.000 transacciones en Total. Datos, veamos primero la composición de los datos:
[['XTZ', 1590981301905, 2.905, 0.4, 'False\n'],
['XTZ', 1590981303044, 2.903, 3.6, 'True\n'],
['XTZ', 1590981303309, 2.903, 3.7, 'True\n'],
['XTZ', 1590981303738, 2.903, 238.1, 'True\n'],
['XTZ', 1590981303892, 2.904, 0.1, 'False\n'],
['XTZ', 1590981305250, 2.904, 0.1, 'False\n'],
['XTZ', 1590981305643, 2.903, 197.3, 'True\n'],
Los datos son una lista bidimensional, ordenada por tiempo de transacción. Los significados específicos son: nombre del producto, precio de la transacción, marca de tiempo de la transacción, cantidad de la transacción y si es una transacción de orden de venta activa. Hay compradores y vendedores, y cada transacción incluye un comprador y un vendedor. Si el comprador es un creador de mercado y el vendedor es un tomador, el último dato es Verdadero.
En primer lugar, en función de la dirección de la transacción, se pueden inferir con bastante precisión los precios de compra y venta en el mercado. Si se trata de una orden de venta activa, el precio de compra en ese momento es el precio de la transacción. Si se trata de una orden de compra activa, el precio de la transacción es el precio de la transacción. El precio de venta es el precio de la transacción. Si hay una nueva transacción, se actualizará la nueva cotización. Si no se actualiza, se mantendrá el resultado anterior. Es fácil deducir que en el último momento de los datos anteriores, el precio de compra era 2,903 y el precio de venta era 2,904.
De acuerdo con el flujo de órdenes, la correspondencia se puede realizar de la siguiente manera: tomando una orden de compra como ejemplo, el precio es precio, la cantidad de la orden es monto y las órdenes de compra y venta son oferta y demanda respectivamente. Si el precio es inferior al de venta y superior al de oferta, primero se lo juzga como creador y se lo puede vincular con la transacción primero. Luego, dentro del tiempo de existencia de la orden, todas las transacciones con un precio de transacción inferior o igual a El precio se corresponderá con esta orden (si el precio es inferior al de venta, el precio de la transacción es superior al de oferta). Si el precio de oferta es igual o superior al de oferta, no se puede negociar primero. Todas las órdenes con un precio de transacción inferior al precio que se corresponderá con esta orden. El precio de correspondencia es el precio y el volumen de transacción es el volumen de transacción de cada transacción hasta que la orden se ejecute por completo o se cancele. Si el precio es superior al precio de venta, se considera que es un comprador. Después de eso, todas las transacciones con un precio de transacción inferior o igual al precio dentro del tiempo de existencia de la orden se emparejarán con esta orden, y el precio de emparejamiento se aplicará. sea el precio de transacción de la transacción. La distinción entre creadores y tomadores se debe a que las bolsas básicamente incentivan la colocación de órdenes y ofrecen tarifas preferenciales por transacción. En el caso de las estrategias de alta frecuencia, esta distinción debe tenerse en cuenta.
Es fácil ver un problema con este tipo de emparejamiento. Si la orden es un tomador, la situación real es que se puede ejecutar inmediatamente, en lugar de esperar nuevas órdenes para emparejarla. En primer lugar, no tomamos en cuenta el volumen de órdenes pendientes. Incluso si hubiera datos, juzgar directamente la transacción cambiaría la profundidad y afectaría al mercado. La combinación de órdenes nuevas equivale a sustituir las órdenes reales del historial por las suyas. En cualquier caso, no superará el límite del volumen de negociación propio del mercado y el beneficio final no superará el beneficio máximo generado por el mercado. Algunos mecanismos de coincidencia también afectan el volumen de transacciones de órdenes, lo que a su vez afecta los retornos de la estrategia y refleja cuantitativamente la capacidad de la estrategia. No habrá un backtest tradicional en el que la ganancia se duplicará si se duplica la cantidad de fondos.
Hay algunos pequeños detalles. Si el precio de compra de la orden es igual al precio de compra única, en realidad todavía hay cierta probabilidad de que se iguale al precio de compra única. Es necesario considerar la prioridad de la orden pendiente y la probabilidad de transacción, etc. Es relativamente complicado y no se considerará aquí.
Los objetos de intercambio pueden referirse a la introducción inicial, que básicamente no ha cambiado. Solo se agrega la diferencia entre las tarifas de creador y tomador, y se optimiza la velocidad de las pruebas retrospectivas. A continuación se presentará principalmente el código correspondiente.
symbol = 'XTZ'
loop_time = 0
intervel = 1000 #策略的休眠时间为1000ms
init_price = data[0][2] #初始价格
e = Exchange([symbol],initial_balance=1000000,maker_fee=maker_fee,taker_fee=taker_fee,log='') #初始化交易所
depth = {'ask':data[0][2], 'bid':data[0][2]} #深度
order = {'buy':{'price':0,'amount':0,'maker':False,'priority':False,'id':0},
'sell':{'price':0,'amount':0,'maker':False,'priority':False,'id':0}} #订单
for tick in data:
price = int(tick[2]/tick_sizes[symbol])*tick_sizes[symbol] #成交价格
trade_amount = tick[3] #成交数量
time_stamp = tick[1] #成交时间戳
if tick[4] == 'False\n':
depth['ask'] = price
else:
depth['bid'] = price
if depth['bid'] < order['buy']['price']:
order['buy']['priority'] = True
if depth['ask'] > order['sell']['price']:
order['sell']['priority'] = True
if price > order['buy']['price']:
order['buy']['maker'] = True
if price < order['sell']['price']:
order['sell']['maker'] = True
#订单网络延时也可以作为撮合条件之一,这里没考虑
cond1 = order['buy']['priority'] and order['buy']['price'] >= price and order['buy']['amount'] > 0
cond2 = not order['buy']['priority'] and order['buy']['price'] > price and order['buy']['amount'] > 0
cond3 = order['sell']['priority'] and order['sell']['price'] <= price and order['sell']['amount'] > 0
cond4 = not order['sell']['priority'] and order['sell']['price'] < price and order['sell']['amount'] > 0
if cond1 or cond2:
buy_price = order['buy']['price'] if order['buy']['maker'] else price
e.Buy(symbol, buy_price, min(order['buy']['amount'],trade_amount), order['buy']['id'], order['buy']['maker'])
order['buy']['amount'] -= min(order['buy']['amount'],trade_amount)
e.Update(time_stamp,[symbol],{symbol:price})
if cond3 or cond4:
sell_price = order['sell']['price'] if order['sell']['maker'] else price
e.Sell(symbol, sell_price, min(order['sell']['amount'],trade_amount), order['sell']['id'], order['sell']['maker'])
order['sell']['amount'] -= min(order['sell']['amount'],trade_amount)
e.Update(time_stamp,[symbol],{symbol:price})
if time_stamp - loop_time > intervel:
order = get_order(e,depth,order) #交易逻辑,这里未给出
loop_time += int((time_stamp - loop_time)/intervel)*intervel
Algunos detalles a tener en cuenta:
Finalmente, hemos llegado a la etapa de backtesting propiamente dicha. Realizaremos un backtesting de una de las estrategias de grid más clásicas para ver si consigue los resultados esperados. El principio de la estrategia es que cada vez que el precio sube un 1%, mantenemos una orden corta de un valor determinado (o viceversa, mantenemos una orden larga), calculamos las órdenes de compra y venta y las colocamos por adelantado. El código no se publica. Encapsular todo el código enGrid('XTZ',100,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)En la función, los parámetros son: par comercial, desviación de precio del 1% del valor de retención, densidad de órdenes del 0,3%, intervalo de suspensión en ms, tarifa del creador de órdenes y tarifa del tomador de órdenes.
En los últimos cinco días, el mercado XTZ ha estado en una fase volátil, lo que es muy adecuado para la red. /subir/activo/1e235fa08ed9dce82a3.png
Primero, realizamos pruebas retrospectivas del impacto de los distintos tamaños de posición en los retornos. Los retornos medidos por el mecanismo de pruebas retrospectivas tradicionales aumentarán definitivamente proporcionalmente al aumento de las posiciones.
e1 = Grid('XTZ',100,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e1.account['USDT'])
e2 = Grid('XTZ',1000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e2.account['USDT'])
e3 = Grid('XTZ',10000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e3.account['USDT'])
e4 = Grid('XTZ',100000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e4.account['USDT'])
Se realizaron pruebas retrospectivas de un total de cuatro grupos, con valores de retención de 100, 1000, 10000 y 100000 respectivamente, y el tiempo total de prueba retrospectiva fue de 1,3 s. Los resultados son los siguientes:
{'realised_profit': 28.470993031132966, 'margin': 0.7982662957624465, 'unrealised_profit': 0.0104554474048441, 'total': 10000028.481448, 'leverage': 0.0, 'fee': -0.3430967859046398, 'maker_fee': -0.36980249726699727, 'taker_fee': 0.026705711362357405}
{'realised_profit': 275.63148945320177, 'margin': 14.346335829979132, 'unrealised_profit': 4.4382117331794045e-14, 'total': 10000275.631489, 'leverage': 0.0, 'fee': -3.3102045933457784, 'maker_fee': -3.5800688964477048, 'taker_fee': 0.2698643031019274}
{'realised_profit': 2693.8701498889504, 'margin': 67.70120400534114, 'unrealised_profit': 0.5735269329348516, 'total': 10002694.443677, 'leverage': 0.0001, 'fee': -33.984021415250744, 'maker_fee': -34.879233866850974, 'taker_fee': 0.8952124516001403}
{'realised_profit': 22610.231198585603, 'margin': 983.3853688758861, 'unrealised_profit': -20.529965947304365, 'total': 10022589.701233, 'leverage': 0.002, 'fee': -200.87094000385412, 'maker_fee': -261.5849078470078, 'taker_fee': 60.71396784315319}
Se puede observar que las ganancias finales realizadas fueron 28,4%, 27,5%, 26,9% y 22,6% del valor de la posición respectivamente. Esto también está en línea con la situación actual. Cuanto mayor sea el valor de la posición, mayor será el valor de la orden pendiente, más probable será que se produzca una transacción parcial y el beneficio final obtenido será menor en relación con el volumen de órdenes pendientes. La siguiente figura compara los rendimientos relativos de las tenencias con valores de 100 y 10.000 respectivamente:

También podemos realizar pruebas retrospectivas del impacto de diferentes parámetros en los retornos de las pruebas retrospectivas, como la densidad de pedidos, el tiempo de inactividad, las tarifas de manejo, etc. Tomando el tiempo de sueño como ejemplo, cámbielo a 100 ms y compárelo con el tiempo de sueño de 1000 ms para ver los beneficios. Los resultados del backtest son los siguientes:
{'realised_profit': 29.079440803790423, 'margin': 0.7982662957624695, 'unrealised_profit': 0.0104554474048441, 'total': 10000029.089896, 'leverage': 0.0, 'fee': -0.3703702128662524, 'maker_fee': -0.37938946377435134, 'taker_fee': 0.009019250908098965}
Las ganancias han aumentado ligeramente. Esto se debe a que la estrategia solo coloca un conjunto de pedidos. Algunos pedidos no pueden beneficiarse de las fluctuaciones de precios porque no se pueden cambiar a tiempo. La reducción del tiempo de inactividad ha mejorado este problema. Esto también ilustra la importancia de colocar múltiples grupos de pedidos en una estrategia de cuadrícula.
Este artículo propone de manera innovadora un nuevo sistema de backtesting basado en el flujo de órdenes, que puede simular parcialmente las condiciones de coincidencia de órdenes pendientes, órdenes de toma, transacciones parciales, demoras, etc., y reflejar parcialmente el impacto de los fondos de estrategia en los retornos. Tiene referencias importantes valor para las estrategias de cobertura, y las pruebas retrospectivas de alta precisión señalan la dirección para optimizar los parámetros de la estrategia. Esto también se ha verificado mediante operaciones reales a largo plazo. También controla mejor la cantidad de datos necesarios para el backtesting, y la velocidad del backtesting también es muy rápida.