Cuando escribíInvestigación sobre la estrategia de cobertura de divisas de futuros de Binance, también lancé un motor de backtest. Y el primer informe se basó en el backtest de K-line de una hora, que verificó la efectividad de la estrategia. Pero el tiempo de sueño de la estrategia de código abierto real es
En primer lugar, ¿qué es la línea K histórica? Los datos de la línea K contienen cuatro precios de alto, abierto, bajo, cerrado, las dos primeras
La primera es la cuestión del tiempo. El tiempo del precio más alto y el precio más bajo de los datos de la línea K no se dan y no necesitan ser considerados, pero los precios de apertura y cierre más importantes no son el tiempo de apertura y cierre. Incluso las variedades comerciales menos populares a menudo no tienen comercio por más de diez segundos, y cuando hacemos pruebas de retroceso a la estrategia de múltiples variedades, a menudo asumimos que su precio de apertura y precio de cierre son los mismos, que también se basa en la prueba de retroceso del precio de cierre.
Imagínese usar la línea de nivel de minuto K para probar el arbitraje de dos variedades. La diferencia entre ellas es generalmente de 10 yuanes ((o dólares). Ahora, a las 10:01, el precio de cierre del contrato A es de 100, el contrato B es de 112 y la diferencia es de 12 yuanes. Así que la estrategia comienza a cubrirse. En cierto momento, la diferencia de precio regresó, y la estrategia obtuvo una ganancia de retorno de 2 yuanes.
Pero la situación real puede ser que a las 10:00:45, el contrato A produjo una transacción de 100 yuanes, después de lo cual no hubo transacción, el contrato B tuvo una transacción de 112 yuanes a las 10:00:58, a las 10:01:00 Ambos precios no existen. ¿Cuál es el precio de mercado en este momento, y cuánto puede obtener la operación de cobertura? No puedo saber. Una situación posible es: a las 10:00:58, el precio de la orden pendiente de 101.9
En el102.1
, y no hay diferencia de 2 yuanes en absoluto.
El segundo es el problema de emparejamiento. El emparejamiento real es la prioridad de precio y la prioridad de tiempo. Si el comprador excede el precio de
El último es el impacto de la estrategia en sí misma en el mercado. Si se trata de una prueba de retroceso de fondos de pequeña cantidad, el impacto no es grande. Pero si el volumen de transacciones es grande, tendrá un impacto en el mercado. No solo el deslizamiento de precios será grande cuando colocas una orden de gran volumen, si compras una orden larga ejecutada, este tipo de acción realmente aprovecha las órdenes de otros comerciantes que originalmente querían comprar, el efecto "mariposa" tendrá un impacto en el mercado. Este efecto no se puede cuantificar. Solo podemos decir por experiencia que el comercio de alta frecuencia solo puede acomodar pequeños fondos.
FMZ proporciona backtest de nivel real, que puede obtener datos históricos reales20 layer depth price
, de segundo nivel en tiempo realTicks
, Each Individual Transaction
Basándose en estas características, FMZ creó una función de reproducción de transacciones en tiempo real.
Este tipo de cantidad de datos de backtest es muy grande, y la velocidad de backtest también es muy lenta, generalmente solo puede backtest durante dos días. Para estrategias de frecuencia relativamente alta o de tiempo crítico, es necesaria una backtest a nivel de mercado real.
El mecanismo de emparejamiento actual es que si la orden de compra es mayor que el
Hay muy poca información en la línea K, y la profundidad del precio también puede ser una profundidad falsa, pero hay un tipo de datos que es la voluntad de transacción real del mercado, que refleja el historial de transacciones más real, es decir,Each Individual Transaction
Este artículo propondrá un sistema de backtest de alta frecuencia basado en el flujo de pedidos, que reducirá en gran medida el volumen de datos de backtest a nivel de mercado real y, en cierta medida, simulará el impacto del volumen de operaciones en el mercado.
He descargado la transacción de los últimos 5 días Binance XTZ contrato perpetuo (dirección de descarga:https://www.fmz.com/upload/asset/1ff487b007e1a848ead.csv), como una variedad poco popular, tiene un total de 213000 datos de transacciones, 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 en orden cronológico. Los significados específicos son los siguientes: nombre de variedad, precio de la transacción, marca de tiempo de la transacción, cantidad de la transacción, si se trata de una transacción activa de orden de venta.Maker
y el vendedor es un activoTaker
, los últimos datos sonTrue
.
En primer lugar, de acuerdo con la dirección de la transacción, puede especular con bastante precisión sobre el
De acuerdo con el flujo de pedidos, se puede emparejar de la siguiente manera: tomar una orden de compra como ejemplo, el precio esprice
, la cantidad de pedido esamount
, entonces comprar y vender 1 en este momento sonbid
yask
En el caso de losprice
es inferior aask
y superior abid
, entonces se juzga comomaker
Primero, y la prioridad se puede igualar para hacer un trato, entonces todos los tratos con un precio de transacción inferior o igual a laprice
durante el tiempo de existencia de la orden se combinará con este orden (siprice
es menor o igual abid
, no se da prioridad a la transacción.price
se corresponden con este orden.)
El precio correspondiente esprice
, y el volumen es el volumen de transacciones deEach Individual Transaction
, hasta que el pedido se complete por completo o se cancele.ask
, se juzga como untaker
Después de eso, durante el tiempo en que existe la orden, todas las operaciones con un precio de transacción inferior o igual aprice
se coinciden con esta orden, y el precio de coincidencia es el precio de transacción de laEach Individual Transaction
La distinción entremaker
ytaker
En el caso de las estrategias de alta frecuencia, esta diferencia debe tenerse en cuenta.
Es fácil ver un problema con este tipo de coincidencia.taker
En primer lugar, no consideramos el volumen de órdenes pendientes, incluso si hay algunos datos, directamente juzgar la transacción también ha cambiado la profundidad del precio, afectando al mercado.
Basado en el emparejamiento de nuevas órdenes, es equivalente a reemplazar las órdenes existentes en el historial con sus órdenes. En cualquier caso, no excederá el límite del propio volumen de negociación del mercado, y la ganancia final no puede exceder la ganancia máxima generada por el mercado. Parte del mecanismo de emparejamiento también afecta el volumen de órdenes, que a su vez afecta los ingresos de la estrategia, lo que refleja cuantitativamente la capacidad de la estrategia.
Si el precio de compra de la orden es igual a
Los objetos de intercambio pueden referirse a la introducción al principio, básicamente sin cambios, sólo añadiendo la diferencia entremaker
ytaker
En la actualidad, la mayoría de los sistemas de prueba de compatibilidad se utilizan para realizar pruebas de compatibilidad con los sistemas de prueba de compatibilidad.
symbol = 'XTZ'
loop_time = 0
intervel = 1000 # The sleep time of the strategy is 1000ms
init_price = data[0][2] # Initial price
e = Exchange([symbol],initial_balance=1000000,maker_fee=maker_fee,taker_fee=taker_fee,log='') # Initialize the exchange
depth = {'ask':data[0][2], 'bid':data[0][2]} # depth
order = {'buy':{'price':0,'amount':0,'maker':False,'priority':False,'id':0},
'sell':{'price':0,'amount':0,'maker':False,'priority':False,'id':0}} # order
for tick in data:
price = int(tick[2]/tick_sizes[symbol])*tick_sizes[symbol] # executed price
trade_amount = tick[3] # executed volume
time_stamp = tick[1] # executed timestamp
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
# Order network delay can also be used as one of the matching conditions, not considered here
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) # Trading logic, not given here
loop_time += int((time_stamp - loop_time)/intervel)*intervel
Algunos detalles a tener en cuenta:
Cuando hay una nueva transacción, primero debemos hacer coincidir el pedido, y luego colocar el pedido de acuerdo con el último precio.
Cada orden tiene dos atributos: creadormaker
, y cuando el precio de compra es mayor que Priority matching
, priority
determina si el precio es igual o no al precio de compra, y el fabricante determina la comisión de transacción.
Elmaker
ypriority
Cuando el precio es mayor que el precio de compra, el volumen restante será el valor de la compra.maker
.
Estrategiainterval
En el caso de la Comisión, la Comisión no puede hacer nada.
Finalmente, es la etapa de backtest real. Vamos a backtest una de las estrategias de la cuadrícula más clásica aquí para ver si podemos lograr los resultados esperados. El principio de la estrategia es que cada vez que el precio aumenta en un 1%, mantenemos una orden corta de un cierto valor (inversamente, mantenemos una orden larga), calcular la orden de compra y la orden de venta por adelantado.Grid('XTZ', 100, 0.3, 1000, maker_fee=-0.00002, taker_fee=0.0003)
función, los parámetros son: el par de operaciones, el precio se desvía del valor de retención de 1%, la densidad de órdenes pendientes es de 0.3%, el intervalo de reposoms
, comisiones por órdenes pendientes y comisiones por órdenes ejecutadas.
El precio de mercado de XTZ
En primer lugar, se hace un backtest sobre el efecto de las diferentes posiciones de tenencia en el rendimiento de los beneficios.
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'])
Un total de cuatro grupos fueron sometidos a backtest, el valor de las posiciones de tenencia fue de 100, 1000, 10000, 100.000, y el tiempo total de backtest 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 ver que las ganancias realizadas finales son de 28.4%, 27.5%, 26.9% y 22.6% del valor de la posición de tenencia respectivamente. Esto también está en línea con la situación real. Cuanto mayor sea el valor de la posición de tenencia, mayor sea el valor de la orden pendiente, más probable es que se produzca una transacción parcial, y menor sea la ganancia realizada final en relación con el monto de la orden pendiente.
También podemos hacer pruebas de retroceso del impacto de diferentes parámetros en los ingresos de las pruebas de retroceso, como la densidad de pedidos pendientes, el tiempo de sueño, la tarifa de transacción, etc. Tomemos el tiempo de sueño como ejemplo, cambiémoslo a 100 ms y comparemos el tiempo de sueño a 1000 ms para ver el retorno de ganancias. Los resultados de las pruebas de retroceso 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}
Los ingresos han aumentado un poco, porque la estrategia sólo envía un conjunto de pedidos, algunos pedidos no serán capaces de ejecutar los precios fluctuantes porque no tienen tiempo para cambiar, y la reducción del tiempo de sueño mejora este problema.
Este artículo propone innovadoramente un nuevo sistema de backtest basado en el flujo de pedidos, que puede simular parcialmente la situación de coincidencia de pedidos pendientes, pedidos ejecutados, pedidos ejecutados parcialmente, retrasos, etc., y refleja parcialmente el impacto de la cantidad de fondos de estrategia en los ingresos. Para estrategias de alta frecuencia y cobertura, tiene un valor de referencia importante.