Type/to search
8
Follow
1369
Followers
Algunas reflexiones sobre la lógica del trading de futuros de monedas digitales
Discussions
Created 2020-06-01 09:52:45  Updated 2023-10-08 19:41:25
 6
 2787

img

Algunas reflexiones sobre la lógica del trading de futuros de monedas digitales

Escenario del problema

Durante mucho tiempo, el problema del retraso de datos de la interfaz API de posición de cambio de moneda digital siempre me ha molestado. Todavía no he encontrado una solución adecuada, así que reproduciré este problema. Generalmente la orden de mercado proporcionada por el intercambio de contratos es en realidad el precio de la contraparte, por lo que a veces el uso de esta denominada "orden de mercado" no es confiable. Por lo tanto, cuando escribimos estrategias de negociación de futuros de monedas digitales, la mayoría de nosotros utilizamos órdenes limitadas. Después de colocar cada orden, debemos verificar la posición para ver si la orden se ha ejecutado y si la posición correspondiente se mantiene. El problema radica en esta información de posición. Si se ejecuta la orden, los datos devueltos por la interfaz de información de posición de la bolsa (es decir, la interfaz de bolsa a la que realmente se accede cuando llamamos a exchange.GetPosition) deberían incluir la información de la posición recién abierta. Sin embargo, si los datos devueltos por el intercambio son datos antiguos, es decir, la información de posición antes de que se ejecutara la orden recién colocada, entonces habrá un problema. La lógica comercial puede pensar que la orden no se ha ejecutado y continuar colocando la orden. Sin embargo, la interfaz de colocación de órdenes de la bolsa no sufre retrasos, sino que las transacciones se completan muy rápidamente y las órdenes se ejecutan tan pronto como se colocan. Esto tendrá como consecuencia grave que la estrategia coloque órdenes repetidamente cuando se active una operación de apertura.

Experiencia real

Debido a este problema, vi una estrategia que abrió una posición larga loca. Afortunadamente, el mercado estaba en auge en ese momento y la ganancia flotante superó los 10 BTC. Afortunadamente, el mercado está en auge; si se hubiera desplomado, el resultado sería predecible.

Intentar resolverlo

  • Solución 1
    La lógica de órdenes de la estrategia se puede diseñar para colocar solo una orden, y el precio de la orden es el precio del oponente en ese momento más un deslizamiento mayor, para así tomar órdenes del oponente de cierta profundidad. La ventaja de hacer esto es que solo realizas un pedido una vez y no se basa en información de posición. Esto puede evitar el problema de órdenes duplicadas, pero a veces colocar una orden cuando el precio cambia mucho puede activar el mecanismo de límite de precio del intercambio, y es posible que incluso con un gran deslizamiento, la orden aún no se ejecute, perdiendo así la oportunidad. .

  • Solución 2
    Utilice la función de orden de mercado del exchange y pase -1 en FMZ como precio, que es una orden de mercado. Actualmente, la interfaz de futuros de OKEX se ha actualizado para admitir órdenes de mercado reales.

  • Solución 3
    Todavía utilizamos la lógica comercial anterior y colocamos órdenes utilizando órdenes limitadas, pero agregamos algunas detecciones a la lógica comercial para intentar resolver el problema causado por el retraso en los datos de posición. Compruebe si el pedido desaparece de la lista de pedidos pendientes sin cancelarse después de realizar el pedido (hay dos posibilidades de desaparición de la lista de pedidos pendientes: 1 cancelación y 2 cumplimiento). Si se detecta tal situación y la cantidad del pedido y el pedido El volumen es el mismo que la última vez. En este momento, debe prestar atención a si los datos de posición están retrasados. Deje que el programa ingrese a la lógica de espera para volver a adquirir la información de posición. Incluso puede continuar optimizando y aumentando el número. de activación de esperas. Si supera un número determinado, significa que los datos de la interfaz de posición se retrasan. El problema es grave y se termina la lógica de esta transacción.

Diseño basado en el esquema 3

javascript
// 参数 /* var MinAmount = 1 var SlidePrice = 5 var Interval = 500 */ function GetPosition(e, contractType, direction) { e.SetContractType(contractType) var positions = _C(e.GetPosition); for (var i = 0; i < positions.length; i++) { if (positions[i].ContractType == contractType && positions[i].Type == direction) { return positions[i] } } return null } function Open(e, contractType, direction, opAmount) { var initPosition = GetPosition(e, contractType, direction); var isFirst = true; var initAmount = initPosition ? initPosition.Amount : 0; var nowPosition = initPosition; var directBreak = false var preNeedOpen = 0 var timeoutCount = 0 while (true) { var ticker = _C(e.GetTicker) var needOpen = opAmount; if (isFirst) { isFirst = false; } else { nowPosition = GetPosition(e, contractType, direction); if (nowPosition) { needOpen = opAmount - (nowPosition.Amount - initAmount); } // 检测directBreak 并且持仓未变的情况 if (preNeedOpen == needOpen && directBreak) { Log("疑似仓位数据延迟,等待30秒", "#FF0000") Sleep(30000) nowPosition = GetPosition(e, contractType, direction); if (nowPosition) { needOpen = opAmount - (nowPosition.Amount - initAmount); } /* timeoutCount++ if (timeoutCount > 10) { Log("连续10次疑似仓位延迟,下单失败!", "#FF0000") break } */ } else { timeoutCount = 0 } } if (needOpen < MinAmount) { break; } var amount = needOpen; preNeedOpen = needOpen e.SetDirection(direction == PD_LONG ? "buy" : "sell"); var orderId; if (direction == PD_LONG) { orderId = e.Buy(ticker.Sell + SlidePrice, amount, "开多仓", contractType, ticker); } else { orderId = e.Sell(ticker.Buy - SlidePrice, amount, "开空仓", contractType, ticker); } directBreak = false var n = 0 while (true) { Sleep(Interval); var orders = _C(e.GetOrders); if (orders.length == 0) { if (n == 0) { directBreak = true } break; } for (var j = 0; j < orders.length; j++) { e.CancelOrder(orders[j].Id); if (j < (orders.length - 1)) { Sleep(Interval); } } n++ } } var ret = { price: 0, amount: 0, position: nowPosition }; if (!nowPosition) { return ret; } if (!initPosition) { ret.price = nowPosition.Price; ret.amount = nowPosition.Amount; } else { ret.amount = nowPosition.Amount - initPosition.Amount; ret.price = _N(((nowPosition.Price * nowPosition.Amount) - (initPosition.Price * initPosition.Amount)) / ret.amount); } return ret; } function Cover(e, contractType, opAmount, direction) { var initPosition = null; var position = null; var isFirst = true; while (true) { while (true) { Sleep(Interval); var orders = _C(e.GetOrders); if (orders.length == 0) { break; } for (var j = 0; j < orders.length; j++) { e.CancelOrder(orders[j].Id); if (j < (orders.length - 1)) { Sleep(Interval); } } } position = GetPosition(e, contractType, direction) if (!position) { break } if (isFirst == true) { initPosition = position; opAmount = Math.min(opAmount, initPosition.Amount) isFirst = false; } var amount = opAmount - (initPosition.Amount - position.Amount) if (amount <= 0) { break } var ticker = _C(exchange.GetTicker) if (position.Type == PD_LONG) { e.SetDirection("closebuy"); e.Sell(ticker.Buy - SlidePrice, amount, "平多仓", contractType, ticker); } else if (position.Type == PD_SHORT) { e.SetDirection("closesell"); e.Buy(ticker.Sell + SlidePrice, amount, "平空仓", contractType, ticker); } Sleep(Interval) } return position } $.OpenLong = function(e, contractType, amount) { if (typeof(e) == "string") { amount = contractType contractType = e e = exchange } return Open(e, contractType, PD_LONG, amount); } $.OpenShort = function(e, contractType, amount) { if (typeof(e) == "string") { amount = contractType contractType = e e = exchange } return Open(e, contractType, PD_SHORT, amount); }; $.CoverLong = function(e, contractType, amount) { if (typeof(e) == "string") { amount = contractType contractType = e e = exchange } return Cover(e, contractType, amount, PD_LONG); }; $.CoverShort = function(e, contractType, amount) { if (typeof(e) == "string") { amount = contractType contractType = e e = exchange } return Cover(e, contractType, amount, PD_SHORT); }; function main() { Log(exchange.GetPosition()) var info = $.OpenLong(exchange, "quarter", 100) Log(info, "#FF0000") Log(exchange.GetPosition()) info = $.CoverLong(exchange, "quarter", 30) Log(exchange.GetPosition()) Log(info, "#FF0000") info = $.CoverLong(exchange, "quarter", 80) Log(exchange.GetPosition()) Log(info, "#FF0000") }

Dirección de la plantilla: https://www.fmz.com/strategy/203258

La forma de llamar a la interfaz de plantilla es la misma que en la función principal anterior.$.OpenLong$.CoverLong
La plantilla es una versión beta. Se aceptan sugerencias y comentarios. Continuaremos optimizándola para solucionar el problema del retraso en los datos de posición.

Related Recommendations
Comment
All comments (6)

    最好的办法应该是用ws,订单一有更新让服务器马上通知你,而不是一次次去询问

    6 years ago

    然鹅,WS接口也有不靠谱的时候,惹气麻烦比REST协议更甚。。

    6 years ago

    ws基本不会出问题,就算关键时候断线了,建立好重连机制也不会有问题;当然也有完全的解决方法,这你得自己摸索了

    6 years ago

    遇到过不稳定的WS ,各种故障。各有利弊吧。

    6 years ago

    碰到过这个问题,我的解决办法是记录一下下单前的持仓,然后下ioc订单后记录id,循环获取订单状态,如果是成交/部分成交,循环对比当前持仓和记录的持仓,当这两个值不同就跳出循环。

    6 years ago

    好的感谢, 学习下。

    6 years ago
  • 1
Forums
PINE Language
Get the app
iPhone Download
© 2015 - ∞ INVENTOR PTE LTD (SG)