2
Seguir
439
Seguidores

Una exploración práctica de las estrategias de arbitraje de entrega al contado: los obstáculos entre lo ideal y la realidad

Creado el: 2025-11-28 14:22:49, Actualizado el: 2025-12-16 11:31:06
comments   0
hits   345

Una exploración práctica de las estrategias de arbitraje de entrega al contado: los obstáculos entre lo ideal y la realidad

Prefacio

Hace poco, un amigo me preguntó si podía crear una estrategia de arbitraje, algo que faltaba en la plataforma Inventor. Pensé que no sería difícil, pero me llevó casi un mes conseguir que la lógica básica funcionara. Mirando hacia atrás, los obstáculos que encontré desde la idea inicial hasta su implementación fueron mucho más numerosos de lo que imaginaba.

Este artículo documenta los problemas prácticos encontrados y las soluciones desarrolladas durante el desarrollo de esta estrategia de arbitraje.Sólo para fines de aprendizaje y referencia; no tiene valor práctico de inversión.

La lógica básica de la estrategia

Existe una diferencia de precio entre el contrato de entrega y el precio spot, que normalmente fluctúa en torno a un promedio determinado. Cuando la diferencia de precio se desvía demasiado, teóricamente existen oportunidades de arbitraje.

La idea inicial era sencilla:

  • Monitorear el diferencial de precios entre los contratos spot y de entrega
  • Abrir una posición cuando la diferencia de precio exceda 2 veces la desviación estándar.
  • Obtenga ganancias cerrando posiciones cuando la diferencia de precio vuelva a su valor original.

Suena genial, ¿verdad? Pero en la práctica, descubrirás que hay innumerables detalles que gestionar simplemente al abrir una posición.

La primera trampa: la estabilidad de los diferenciales de precios

Inicialmente, utilizamos la desviación del diferencial de precios como indicador directo, pero descubrimos que, en ocasiones, este seguía ampliándose y nunca volvía a su estado anterior. Más tarde, nos dimos cuenta de que…No todos los diferenciales de precios son estables.

Especialmente a medida que se acerca la fecha de entrega, el comportamiento del spread puede cambiar. Por lo tanto, se añadió la prueba ADF para determinar si la serie de spreads es estacionaria.

function adfTest(series, maxLag=null){
  const n = series.length;
  if(n<10) throw new Error('series too short');
  if(maxLag===null) maxLag = Math.floor(12*Math.pow(n/100, 1/4));
  
  // ... ADF检验的核心计算逻辑
  
  const res = ols(rows, Ys);
  const tstat = tStat(res.beta, res.cov, 1);
  return { tStat: tstat, pValue: pval, usedLag: p };
}

Inicialmente, añadimos varias pruebas, como la prueba de razón de varianza, la prueba de vida media y la prueba KS, pero descubrimos que un exceso de pruebas reducía significativamente el número de oportunidades para abrir posiciones. Finalmente, simplificamos el proceso a solo la prueba ADF y establecimos el umbral del valor p en 0,1.

Lo más importante es que se agregó uno extra.Contador de fallos continuos

if (!adfPass) {
  stationarityFailCount[deliverySymbol] = (stationarityFailCount[deliverySymbol] || 0) + 1;
} else {
  stationarityFailCount[deliverySymbol] = 0;
}

let consecutiveFails = stationarityFailCount[deliverySymbol];
let canTrade = consecutiveFails < CONFIG.consecutiveFailThreshold;

Se prohíbe operar si la prueba falla tres veces consecutivas. Esto puede evitar la apertura de posiciones a ciegas cuando el mercado se encuentra en un estado anormal.

La segunda trampa: la confusión en torno a las estadísticas de ganancias y pérdidas en tiempo real

Calcular las ganancias y pérdidas de una cuenta de futuros es sencillo; basta con observar las fluctuaciones en USDT. Pero las cuentas al contado son diferentes; contienen tanto USDT como criptomonedas. ¿Cómo se calcula esto?

He aquí un detalle que se pasa por alto fácilmente:El costo de mantener bienes al contado cambiará con el comercio.Por ejemplo, si compra una moneda por 100 USDT, la vende por 90 USDT y luego la recompra por 85 USDT, su costo base ya no es el precio inicial de 100 USDT. Usar simplemente el precio congelado al abrir la posición para calcular el valor de la moneda no reflejará la verdadera situación de ganancias y pérdidas.

El enfoque correcto esExtraiga el precio de transacción promedio real del objeto de pedido.

let openSpotPrice = (openSpotOrder && openSpotOrder.AvgPrice) ? 
  openSpotOrder.AvgPrice : record.openSpotPrice;
let closeSpotPrice = closeSpotOrder.AvgPrice || currentPair.spotPrice;

Luego, la tasa de retorno se calcula en función del precio real de la transacción:

// 正套:买现货+卖期货
if (record.direction === 'positive') {
  spotReturnRate = (closeSpotPrice - openSpotPrice) / openSpotPrice;
  deliveryReturnRate = (openDeliveryPrice - closeDeliveryPrice) / openDeliveryPrice;
} else {
  // 反套:卖现货+买期货
  spotReturnRate = (openSpotPrice - closeSpotPrice) / openSpotPrice;
  deliveryReturnRate = (closeDeliveryPrice - openDeliveryPrice) / openDeliveryPrice;
}

let totalReturnRate = spotReturnRate + deliveryReturnRate;
let requiredUSD = openSpotPrice * record.spotAmount;
let actualTotalPnl = totalReturnRate * requiredUSD;

Tenga en cuenta la lógica del cálculo de ganancias y pérdidas aquí:

  • Conjunto regularEn ese momento, el mercado al contado estaba largo y el mercado de futuros estaba corto, por lo que la ganancia/pérdida del mercado al contado = (precio de cierre - precio de apertura) / precio de apertura, y la ganancia/pérdida del mercado de futuros = (precio de apertura - precio de cierre) / precio de apertura.
  • contrarrestarEn ese momento, el trading al contado implica posiciones cortas, mientras que el trading de futuros implica posiciones largas, en direcciones opuestas.

Finalmente, la ganancia o pérdida real de cada transacción se suma a la ganancia o pérdida total:

accumulatedProfit += actualTotalPnl;
_G('accumulatedProfit', accumulatedProfit);

La tercera gran trampa: la trampa de la liquidez

Este es el verdadero problema. ¿Por qué, tras 10 años de funcionamiento, la Plataforma Cuantitativa Inventor cuenta con tan pocas estrategias de arbitraje para contratos de futuros? La respuesta es sencilla:Liquidez insuficiente en el mercado de contratos de entrega

Pregunta 1: Transacción de una sola pierna

El arbitraje no es un cuento de hadas donde se abren posiciones simultáneamente. La realidad es:

  • La orden al contado se ha ejecutado, pero la orden de futuros aún está pendiente.
  • O bien se ejecutó la orden de futuros, pero se canceló la orden al contado.

Este es un ejemplo clásico de “riesgo unilateral”. Una pierna está dentro, mientras que la otra permanece fuera. En este punto, cualquier fluctuación de precio ya no es arbitraje, sino una posición unilateral.

La solución es unirseMecanismo de reversión

if (!deliveryOrder) {
  Log('❌ 期货卖单失败,回滚现货');
  exchanges[0].CreateOrder(pair.spotSymbol, 'sell', -1, spotAmount);
  addCooldown(pair.deliverySymbol, pair.coin, '期货卖单失败,已回滚现货');
  return false;
}

Si alguna de las piernas falla, coloque inmediatamente una orden de mercado para cerrar la pierna ya ejecutada, reduciendo así la exposición al riesgo de esa pierna individual.

Pregunta 2: Las órdenes de mercado también pueden ser rechazadas.

Aún más absurdo, a veces las órdenes de mercado también fallan. Esto podría deberse a controles de riesgo cambiario o a una profundidad de mercado insuficiente; en resumen, la orden simplemente no se ejecuta.

Así que lo hice.Mecanismo dual de orden de mercado + orden límite

function createOrderWithFallback(exchange, symbol, direction, amount, limitPrice, orderType, maxRetry = 3) {
  let useMarketOrder = (limitPrice === -1);
  
  // 先尝试限价单
  if (!useMarketOrder) {
    orderId = exchange.CreateOrder(symbol, direction, limitPrice, amount);
    if (!orderId) {
      Log(`❌ 限价单提交失败,改用市价单`);
      useMarketOrder = true;
    }
  }
  
  // 限价单失败则用市价单
  if (useMarketOrder && !orderId) {
    orderId = exchange.CreateOrder(symbol, direction, -1, marketAmount);
  }
  
  // ... 检查订单状态,失败则重试
}

El sistema puede volver a intentarlo un máximo de 3 veces, y en cada intento utilizará una orden de mercado como red de seguridad.

Pregunta 3: La trampa del monto en las órdenes de compra al contado

Esta trampa está particularmente bien escondida y requiere precaución adicional. La cantidad para una orden de mercado de futuros es…Número de monedasSin embargo, la cantidad solicitada al comprar una orden en el mercado al contado es…Monto en USDT

Aquí se ha añadido específicamente una lógica de conversión:

function getActualAmount(useMarket) {
  if (isSpotBuy && useMarket) {
    // 现货市价买单:需要用USDT金额
    let currentPrice = getDepthMidPrice(exchange, symbol);
    let usdtAmount = amount * currentPrice;
    Log(`  💡 现货买单转换: ${amount.toFixed(6)} 币 → ${usdtAmount.toFixed(4)} USDT`);
    return usdtAmount;
  }
  return amount;
}

La cantidad de criptomoneda utilizada en una orden limitada se convierte automáticamente a USDT para una orden de mercado.

La cuarta trampa: la ilusión de oportunidades de arbitraje

Otro problema frustrante es que se detecta una señal de arbitraje y usted está listo para abrir una posición, pero la oportunidad ya ha desaparecido en el momento en que realiza la orden.

Los precios fluctúan en tiempo real, y las condiciones del mercado pueden haber cambiado entre la detección de la señal y la ejecución de una posición. Los diferenciales de precios pueden haberse reducido y las oportunidades de arbitraje pueden haber desaparecido. Si sigue abriendo una posición insensatamente en este punto, simplemente está desperdiciando comisiones.

Así que se añadió.Mecanismo de confirmación secundaria

// 开仓前重新获取实时价格并验证套利机会
Log('🔄 重新获取实时Depth盘口价格并验证套利机会...');

let realtimeSpotPrice = getDepthMidPrice(exchanges[0], pair.spotSymbol, true);
let realtimeDeliveryPrice = getDepthMidPrice(exchanges[1], pair.deliverySymbol, true);

let realtimeSpread = realtimeDeliveryPrice - realtimeSpotPrice;
let realtimeSpreadRate = realtimeSpread / realtimeSpotPrice;

// 重新计算实时Z-Score
let realtimeZScore = (realtimeSpreadRate - mu) / (sigma || 1e-6);

// 验证:实时Z-Score是否仍然满足开仓条件
if (absRealtimeZ < CONFIG.zScoreEntry) {
  Log('❌ 套利机会已消失!');
  Log('  取消开仓,避免亏损');
  return false;
}

Antes de realizar un pedido, vuelva a obtener el precio en tiempo real, vuelva a calcular el puntaje Z y solo ejecute el pedido si está seguro de que la oportunidad aún existe.

La quinta trampa: Problemas heredados relacionados con posiciones de futuros.

En ocasiones, al reiniciar una estrategia o cerrar una posición anterior, pueden quedar posiciones residuales en la cuenta de futuros. Si no se solucionan, las nuevas posiciones se superpondrán con las antiguas, lo que resultará en un tamaño de posición descontrolado.

Así que se añadió.Liquidación forzosa antes de abrir una posiciónLa lógica:

// 检查期货现有仓位并平仓
let existingPosition = getPositionBySymbol(pair.deliverySymbol);

if (existingPosition && Math.abs(existingPosition.Amount) > 0) {
  Log('⚠️ 检测到该合约的现有仓位,执行平仓操作...');
  
  let closeDirection = existingPosition.Type === PD_LONG ? 'closebuy' : 'closesell';
  let closeAmount = Math.abs(existingPosition.Amount);
  
  let closeOrder = createOrderWithFallback(
    exchanges[1],
    pair.deliverySymbol,
    closeDirection,
    closeAmount,
    -1,
    '期货'
  );
  
  if (!closeOrder) {
    Log('❌ 平仓现有持仓失败,终止开仓');
    addCooldown(pair.deliverySymbol, pair.coin, '平仓现有持仓失败');
    return false;
  }
}

Antes de abrir una posición, revísela. Si quedan posiciones, ciérrelas para asegurar que su cuenta esté limpia.

La sexta gran trampa: la trampa del retraso en los datos del Ticker

Este es todo el proceso de desarrollo de la estrategia.El más oculto y el más mortalUno de los problemas.

Después de que la estrategia comenzó a ejecutarse, se observó un fenómeno extraño:

  • Se ha detectado una señal de arbitraje y es momento de abrir una posición.
  • El precio óptimo de la orden límite se calcula sumando y restando la diferencia de precio del precio del ticket.
  • Como resultado, la orden quedó pendiente, a la espera de ser cumplida.
  • Después de esperar mucho tiempo sin que se completara ninguna transacción, el pedido fue cancelado.

¿Intentaste usar órdenes de mercado? El resultado fue aún peor:

  • La orden de mercado se ejecutó exitosamente.
  • Sin embargo, el precio de la transacción fue completamente diferente del diferencial de arbitraje esperado.
  • La oportunidad de arbitraje que se había planeado resultó no rentable después de que se completó la transacción.

¿Qué ocurrió exactamente? Tras comparar repetidamente los datos de operaciones en vivo de la bolsa, finalmente se descubrió el problema:

Ticker vs. Profundidad: La diferencia fundamental entre los datos

Los datos del ticker reflejan el precio de transacción real más reciente.Esto suena bien, pero en los mercados con baja liquidez, como los contratos de entrega, surgen problemas:

时间轴:
10:00:00 - 有人以50000成交了1张合约 → Ticker价格更新为50000
10:00:05 - 盘口挂单:买49800 / 卖50200(但没有成交)
10:00:10 - 盘口挂单:买49850 / 卖50150(但没有成交)
...
10:05:00 - Ticker价格仍然是50000(因为5分钟内没有新的成交)

¿Has notado el problema?El precio del Ticker de 50.000 ya era histórico hace 5 minutos.Sin embargo, el precio real actual del mercado (precio del libro de órdenes) puede haber llegado a ser 4985050150.

Si utiliza el precio de cotización de 50 000 para calcular oportunidades de arbitraje y colocar órdenes limitadas, entonces:

  1. Error de juicioLas señales de arbitraje se calculan en función de precios obsoletos.
  2. Pedido fallidoEl precio de la orden limitada está demasiado lejos del precio real del mercado, lo que hace imposible completar la transacción.
  3. Pérdida de mercadoSe utilizó una orden de mercado para forzar una operación, pero el precio real fue completamente diferente al esperado.

¿Por qué son especialmente poco fiables los tickers para contratos de entrega?

La liquidez de los contratos de entrega es mucho peor que la de los contratos al contado:

  • Mercado al contadoSe produce una gran cantidad de transacciones cada segundo y los precios del Ticker se actualizan casi en tiempo real con muy poco retraso.
  • Contrato de entregaPuede tomar varios minutos o incluso más tiempo para que se realice una transacción; el precio del Ticker se retrasa significativamente.

En el caso de contratos con poca liquidez, la desviación entre el precio del ticker y el precio real del libro de órdenes puede alcanzar:

  • Rango normal: 0,1% - 0,5%
  • Periodo de fluctuación: 1% - 3% o incluso más

Para las estrategias de arbitraje, esta desviación es fatal. La ventaja esperada por la diferencia de precio podría ser solo del 0,5 %, pero el precio real de la transacción resulta ser completamente diferente.

Solución: Reemplace Ticker con datos del disco de profundidad

Dado que Ticker no es confiable, usemos…Datos de profundidad (profundidad del libro de pedidos)

function getDepthMidPrice(exchange, symbol, logDetail = false) {
    let depth = exchange.GetDepth(symbol);
    if (!depth || !depth.Bids || depth.Bids.length === 0 || 
        !depth.Asks || depth.Asks.length === 0) {
        Log(`❌ 获取${symbol}盘口失败`);
        return null;
    }
    
    let bestBid = depth.Bids[0].Price;  // 最优买价
    let bestAsk = depth.Asks[0].Price;  // 最优卖价
    let midPrice = (bestBid + bestAsk) / 2;  // 中间价
    
    if (logDetail) {
        let spread = bestAsk - bestBid;
        let spreadRate = spread / midPrice * 100;
        Log(`📊 ${symbol} 盘口: Bid=${bestBid.toFixed(2)}, Ask=${bestAsk.toFixed(2)}, Mid=${midPrice.toFixed(2)}, Spread=${spread.toFixed(2)} (${spreadRate.toFixed(3)}%)`);
    }
    
    return midPrice;
}

Ventajas de los datos de profundidad:

  • Tiempo realRefleja el estado real actual de la cartera de pedidos, sin ningún retraso.
  • exactitudSu pedido se comparará con estos libros de pedidos y este es el precio real del mercado.
  • OperabilidadLas órdenes limitadas calculadas en función de los precios del libro de órdenes tienen una mayor probabilidad de ejecutarse.

Sistema de estrategia de precios duales

Finalmente adoptadoSolución híbrida de Ticker + Profundidad

1. Utilice Ticker para mantener secuencias de datos históricos.

// 用Ticker更新历史价差序列(保持连续性)
let spotTicker = exchanges[0].GetTicker(pair.spotSymbol);
let deliveryTicker = exchanges[1].GetTicker(pair.deliverySymbol);

pair.spotPrice = spotTicker.Last;
pair.deliveryPrice = deliveryTicker.Last;
pair.spread = pair.deliveryPrice - pair.spotPrice;

// 历史序列用于ADF检验、Z-Score计算
priceHistory[pair.deliverySymbol].push({
    time: Date.now(),
    spreadRate: pair.spread / pair.spotPrice,
    spread: pair.spread,
    spotPrice: pair.spotPrice,
    deliveryPrice: pair.deliveryPrice
});

¿Por qué se sigue usando Ticker para datos históricos? Porque es necesario.Continuidad de datosSi los datos históricos también se representan utilizando profundidad, las fluctuaciones en los precios del libro de órdenes causarán discontinuidades en la secuencia histórica, lo que afectará la precisión del análisis estadístico.

2. Utilice Profundidad para el juicio en tiempo real y la verificación de la apertura de la posición.

// 开仓前用Depth重新验证套利机会
let realtimeSpotPrice = getDepthMidPrice(exchanges[0], pair.spotSymbol, true);
let realtimeDeliveryPrice = getDepthMidPrice(exchanges[1], pair.deliverySymbol, true);

// 基于Depth价格重新计算Z-Score
let realtimeSpread = realtimeDeliveryPrice - realtimeSpotPrice;
let realtimeSpreadRate = realtimeSpread / realtimeSpotPrice;
let realtimeZScore = (realtimeSpreadRate - mu) / (sigma || 1e-6);

// 二次验证:套利机会是否仍然存在
if (Math.abs(realtimeZScore) < CONFIG.zScoreEntry) {
    Log('❌ 套利机会已消失(基于Depth实时价格)');
    return false;
}

3. Calcule el precio de la orden límite utilizando la profundidad.

// 基于Depth价格和平均价差计算限价单价格
let spreadDeviation = realtimeSpread - avgSpread;
let adjustmentRatio = Math.min(
    Math.abs(spreadDeviation) * CONFIG.limitOrderSpreadRatio,
    spreadStd * 0.5
);

if (direction === 'positive') {
    spotLimitPrice = realtimeSpotPrice + adjustmentRatio;
    deliveryLimitPrice = realtimeDeliveryPrice - adjustmentRatio;
} else {
    spotLimitPrice = realtimeSpotPrice - adjustmentRatio;
    deliveryLimitPrice = realtimeDeliveryPrice + adjustmentRatio;
}

El precio de la orden límite calculado de esta manera se basa en el libro de órdenes real, lo que aumenta enormemente la probabilidad de ejecución.

4. Calcule ganancias y pérdidas en tiempo real utilizando Profundidad.

function calculateUnrealizedPnL(record, currentPair) {
    // 优先用Depth价格计算实时盈亏
    let currentSpotPrice = getDepthMidPrice(exchanges[0], currentPair.spotSymbol);
    let currentDeliveryPrice = getDepthMidPrice(exchanges[1], currentPair.deliverySymbol);
    
    // Depth获取失败才回退到Ticker
    if (!currentSpotPrice || !currentDeliveryPrice) {
        currentSpotPrice = currentPair.spotPrice;
        currentDeliveryPrice = currentPair.deliveryPrice;
    }
    
    // 计算盈亏...
}

Comparación de los efectos reales del combate

Problemas con el uso de Ticker:

检测到套利信号(基于Ticker)
→ 计算限价单价格
→ 下单等待
→ 长时间不成交(价格已经不对了)
→ 改用市价单
→ 成交价格和预期差很多
→ 套利失败或微利

Mejoras después de usar Profundidad:

检测到套利信号(基于Ticker历史)
→ 用Depth重新验证(机会仍在)
→ 基于Depth计算限价单价格
→ 下单,价格贴近盘口
→ 较快成交
→ 成交价格符合预期
→ 套利成功

Optimización de precios de órdenes con límite de precio

Si vamos a usar órdenes limitadas, ¿cómo fijamos el precio? Si lo fijamos de forma demasiado agresiva, la transacción no se concretará; si lo fijamos de forma demasiado conservadora, no obtendremos un buen precio.

Basándonos en el precio de profundidad, el enfoque aquí es:Ajustar dinámicamente en función de la desviación entre el diferencial de precios actual y el diferencial de precios promedio.

let spreadDeviation = realtimeSpread - avgSpread;
let adjustmentRatio = Math.min(
  Math.abs(spreadDeviation) * CONFIG.limitOrderSpreadRatio,
  spreadStd * 0.5
);

// 限制调整幅度在合理区间
let minAdjustment = realtimeSpotPrice * 0.0005;
let maxAdjustment = realtimeSpotPrice * 0.005;
adjustmentRatio = Math.max(minAdjustment, Math.min(maxAdjustment, adjustmentRatio));

Si se trata de un conjunto completo (con una gran diferencia de precio):

  • Precio de compra al contado = Punto medio de profundidad + rango de ajuste
  • Precio de venta de futuros = Punto medio de profundidad - Rango de ajuste

Esto permite que las transacciones se completen con una diferencia de precio favorable, evitando al mismo tiempo estar demasiado lejos del libro de órdenes y, por lo tanto, no perder una transacción.

Mecanismo de período de enfriamiento

Cualquier intento fallido de abrir una posición indica un problema en el mercado, que podría deberse a liquidez insuficiente o volatilidad excesiva. En tales casos, no debería intentarlo de nuevo de inmediato; en lugar de eso, mantenga la calma.

Por lo tanto, se añadió una penalización a cada par comercial fallido.Enfriamiento de 10 minutos

function addCooldown(deliverySymbol, coin, reason) {
  pairCooldowns[deliverySymbol] = Date.now() + CONFIG.cooldownDuration;
  Log(`⏸️ ${deliverySymbol} 进入10分钟冷却期`);
  Log(`   原因: ${reason}`);
  _G('pairCooldowns', pairCooldowns);
}

Durante el período de enfriamiento, no se abrirán posiciones para este par comercial para evitar fallas repetidas y desperdicio de tarifas de transacción.

Deficiencias actuales y áreas de mejora

Esta estrategia todavía es sólo un trabajo en progreso y hay muchas áreas que se pueden optimizar:

1. Problema de retraso Actualmente, los precios se obtienen mediante un método de sondeo, lo que genera una latencia significativa. Cambiar a WebSocket para las actualizaciones de precios en tiempo real mejoraría significativamente la velocidad de respuesta.

2. Optimización del control de riesgos El método actual de stop loss es relativamente simple y directo, y puede considerar:

  • Stop loss dinámico (ajustado en función de la volatilidad)
  • Stop-loss basado en el tiempo (liquidación forzada debido a un tiempo de tenencia excesivo)
  • Control de retiro máximo

3. Gestión de deslizamientos La estrategia de precios para órdenes limitadas se puede hacer más inteligente, por ejemplo, ajustándola dinámicamente en función de factores como la profundidad del libro de órdenes y el volumen de transacciones recientes.

4. Otras aplicaciones de los datos de profundidad Puede analizar el desequilibrio de la cartera de órdenes, predecir las tendencias de precios y mejorar la tasa de éxito del arbitraje.

Resumir

Las estrategias de arbitraje suenan atractivas, pero en la práctica está claro que existen innumerables obstáculos entre el ideal y la realidad.

  • Peligros de las pruebas de estacionariedad
  • Errores en las estadísticas de pérdidas y ganancias
  • La trampa de la liquidez insuficiente
  • Los peligros de las transacciones de una sola pierna
  • Peligros del fallo del orden de mercado
  • Errores en la compra al contado
  • La trampa de las oportunidades de arbitraje que desaparecen
  • El pozo de las posiciones residuales
  • El defecto más fatal es el retraso en el mecanismo Ticker.

En particular, la cuestión de los datos de ticker rezagados es un problema en todo el proceso de desarrollo de la estrategia.Los más fáciles de pasar por alto, pero con el mayor impacto.Los inconvenientes. Para los mercados de contratos de entrega con baja liquidez:

Principio fundamental: utilizar Ticker para mantener la continuidad histórica y utilizar Profundidad para aprovechar oportunidades en tiempo real.

  • Ticker es adecuado para el análisis de datos históricos (prueba ADF, cálculo de puntuación Z).
  • La profundidad es adecuada para el juicio en tiempo real y la ejecución de operaciones (verificación de apertura de posición, fijación de precios de órdenes limitadas, cálculo de ganancias y pérdidas).

Este artículo registra los problemas encontrados y las soluciones durante el proceso de exploración y, con suerte, puede proporcionar alguna referencia para todos.Para reiterar, este artículo tiene fines exclusivamente educativos y de debate. El código aún está en desarrollo y no debe utilizarse directamente en operaciones en vivo.

Si usas una estrategia similar, no dudes en conversar conmigo. El mercado es complejo, y es precisamente esta complejidad la que hace que el trading cuantitativo sea tan desafiante.

Código fuente de la estrategia: https://www.fmz.com/strategy/519280