2
Seguir
410
Seguidores

Juego de Aventureros: Implementación de código y aplicación de la estrategia de rollover

Creado el: 2025-12-19 17:06:01, Actualizado el: 2025-12-29 09:04:46
comments   0
hits   353

[TOC]

Juego de Aventureros: Implementación de código y aplicación de la estrategia de rollover

introducción

En el ámbito del trading cuantitativo, la estrategia de posiciones continuas es un tema atractivo, pero a la vez desafiante. Su idea central es lograr un crecimiento compuesto reinvirtiendo las ganancias obtenidas en mercados con tendencia. Este artículo profundizará en cómo traducir esta idea de trading a la lógica de código ejecutable paso a paso, centrándose en el cambio de mentalidad más que en los detalles técnicos. Es importante destacar que, si bien la estrategia de posiciones continuas amplifica las ganancias, también amplifica los riesgos; este artículo es solo para fines de aprendizaje y debate.


I. Análisis en profundidad de la lógica de beneficios de la estrategia de posiciones continuas

1.1 La esencia matemática del rollover

Diagrama de vuelco

La lógica de ganancias de la estrategia de posición continua es esencialmente unaModelo de crecimiento compuestoEntendamos esto usando un ejemplo simplificado:

Operación tradicional única (3 incrementos consecutivos del 10% cada uno):

  • Capital inicial: 100 USDT, apalancamiento 3x
  • Aumento del mercado: (1+10%) × (1+10%) × (1+10%) - 1 = 33,1%
  • Beneficio: 100 × 3 × 33,1% = 99,3 USDT
  • Precio final: 199,3 USDT

Operaciones de rollover (tres operaciones consecutivas, cada una con un incremento del 10%):

  • primera vez100 USDT → Ganancia de 30 USDT → Los fondos se convierten en 130 USDT
    • Cálculo: 100 × 3x apalancamiento × 10% de aumento = 30
  • 2da vez130 USDT → Ganancia de 39 USDT → Los fondos se convierten en 169 USDT
    • Cálculo: 130 × 3x apalancamiento × 10% de aumento = 39
  • 169 USDT → Beneficio de 50,7 USDT → Los fondos aumentaron a 219,7 USDT
    • Cálculo: 169 × 3x apalancamiento × aumento del 10% = 50,7

Resultados de la comparación:

En el mismo escenario donde el mercado sube un 10% tres veces seguidas:

  • transacción únicaGanancia de 99,3 USDT
  • Comercio de rolloverBeneficio de 119,7 USDT
  • Ventajas del interés compuesto20,4 USDT (un aumento de aproximadamente el 20,5%)

De manera similar, con tres aumentos consecutivos del 10% cada vez, la ganancia por una sola operación fue de 99,3 USDT y la ganancia por renovar la posición fue de 119,7 USDT.Esta diferencia es el poder del interés compuesto.

Expresado mediante una fórmula matemática:

// 传统交易:线性增长
最终资金 = 初始资金 × (1 + 杠杆 × 涨幅)

// 滚仓交易:指数增长
最终资金 = 初始资金 × (1 + 杠杆 × 单次涨幅) ^ 滚仓次数

Esto revela la esencia del rollover:Transformar el crecimiento lineal en crecimiento exponencialSin embargo, esto también expuso riesgos:Una sola orden de stop loss podría eliminar todas las ganancias compuestas anteriores.

1.2 Tres cuestiones fundamentales de la estrategia de renovación

Antes de comenzar a escribir cualquier código, necesitamos responder tres preguntas fundamentales desde una perspectiva estratégica:

Pregunta 1: ¿Cuándo empieza? (Primera entrada)
Es necesario determinar la señal de inicio de una tendencia.

Pregunta 2: ¿Cuándo continuar? (Posición adicional de rodadura)
Éste es el núcleo del roll over de posiciones: cómo determinar si la tendencia continuará después de tomar ganancias.

Pregunta 3: ¿Cuándo parar? (Retirarse y observar)

  • Salida proactiva: debilitamiento de la tendencia
  • Salida pasiva: activación del stop loss

Estas tres preguntas determinan el marco de toda la estrategia y ahora las traduciremos a lógica de código una por una.


II. Pregunta 1: ¿Cuándo empezar? — Encontrar el punto de inflexión para la entrada.

Señales de entrada

2.1 El ideal y la realidad de la estrategia de rollover

Primero entendamos el escenario de aplicación ideal para la estrategia de posición continua.

Escenario ideal:
Imagina poder entrar al mercado SHIB cuando empieza a subir desde $0.000001, o establecer una posición justo antes de que una altcoin experimente un aumento repentino. Mediante la rotación continua, 100 USDT podrían potencialmente convertirse en 10,000 USDT o incluso más. Este es el sueño supremo de la estrategia de rotación.Ingrese al mercado antes de que la criptomoneda explote y obtenga retornos diez o incluso cien veces mayores.

La dura realidad:
El problema es, ¿cómo saber qué criptomoneda subirá? ¿Y cuándo?

  • Si usted es propietario de un proyecto o alguien con información privilegiada, es posible que tenga conocimiento previo de noticias positivas.
  • Si usted es un trader habitual, sólo podrá emitir juicios basándose en las señales del mercado.

Para la mayoría de nosotros, capturar con precisión este punto de inflexión es…Para decirlo sin rodeos, todo es cuestión de suerte.No podemos predecir el futuro; sólo podemos intentar aumentar la probabilidad de “ganar el premio gordo” utilizando datos históricos e indicadores técnicos.

2.2 Del ideal a la realidad: entrada simulada basada en indicadores técnicos

Como no podemos predecir qué criptomoneda aumentará, todo lo que podemos hacer es:Establezca un conjunto ejecutable de reglas de entrada y utilice indicadores técnicos para simular señales de “inicio de tendencia”.

Es como pescar en el vasto océano. Aunque no sabemos dónde están los peces grandes, podemos:

  • Observe las ondas en la superficie del agua (fluctuaciones de precios).
  • Analizar la dirección del flujo de agua (dirección de tendencia).
  • Elija las herramientas adecuadas (indicadores técnicos)

Cuando convergen múltiples señales, creemos que una tendencia podría estar a punto de comenzar, así que entramos al mercado para probarla. Si acertamos, seguimos la tendencia y renovamos nuestras posiciones para ganar dinero; si nos equivocamos, reducimos nuestras pérdidas y salimos del mercado inmediatamente.

2.3 Implementación técnica de la señal de entrada

Elección de herramientas técnicas:
Utilizamos el sistema de media móvil dual EMA (EMA5 y EMA10) como herramienta de identificación de tendencias. La razón para elegirlo es simple:

  • Simple, intuitivo y fácil de verificar.
  • Capaz de reaccionar rápidamente a los cambios de precios
  • Los parámetros equilibran la sensibilidad y la estabilidad.

Lógica central:
Al detectar el “cruce dorado” (EMA5 cruzando por encima de EMA10) y el “cruce de la muerte” (EMA5 cruzando por debajo de EMA10) de las medias móviles, se pueden capturar puntos de reversión de tendencia:

  • Cruz dorada → Señal de compra
  • Cruz de la muerte → Señal de venta en corto

El código es:

// 计算EMA指标
var emaFast = TA.EMA(records, FastEMA);  // EMA5
var emaSlow = TA.EMA(records, SlowEMA);  // EMA10

// 获取当前和前一根K线的EMA值
var ema5_current = emaFast[emaFast.length - 1];
var ema5_prev = emaFast[emaFast.length - 2];
var ema10_current = emaSlow[emaSlow.length - 1];
var ema10_prev = emaSlow[emaSlow.length - 2];

// 检测金叉:前一根K线EMA5<=EMA10,当前K线EMA5>EMA10
var bullCross = ema5_prev <= ema10_prev && ema5_current > ema10_current;

// 检测死叉:前一根K线EMA5>=EMA10,当前K线EMA5<EMA10
var bearCross = ema5_prev >= ema10_prev && ema5_current < ema10_current;

// 空仓时等待信号入场
if (bullCross) {
    Log("📈 金叉信号 - 做多");
    openPosition("LONG", currentPrice);
} else if (bearCross) {
    Log("📉 死叉信号 - 做空");
    openPosition("SHORT", currentPrice);
}

Esta sección no profundizará en los detalles de las cruces doradas y las cruces de la muerte; estos son conceptos fundamentales en el trading. La clave es:Necesitamos una señal de entrada clara y cuantificable para desencadenar el inicio del rollover.


III. Pregunta 2: ¿Cuándo continuar? — El mecanismo central del interés compuesto.

Mecanismo de vuelco

3.1 Entendiendo la esencia del rollover: Un juego de aventurero racional

La estrategia de rollover es esencialmenteUn juego de aventuras racionalEntendamos esto usando un escenario completo:

Reglas del juego:

1. 你从交易所账户中拿出100 USDT作为冒险资金
2. 这100 USDT独立管理,与账户其他资金隔离
3. 用这100 USDT开始交易:
   - 赚了 → 盈利加入资金池,继续用更大的资金交易(滚仓)
   - 亏了 → 触发止损,回到空仓状态
4. 重复这个过程,直到:
   - 要么把100 USDT亏完(游戏结束)
   - 要么滚到一个满意的金额(主动退出)

La brillantez de este juego reside en:

  • El riesgo es manejable: la pérdida máxima es de 100 USDT, que no afectará a otros fondos en la cuenta.
  • Ganancias ilimitadas: si la tendencia se alinea, el interés compuesto puede duplicar rápidamente su capital.
  • Reglas bien definidas para la entrada y la salida: reglas claras para tomar ganancias, detener pérdidas y renovar posiciones.

3.2 Diseño del fondo de capital: la clave para lograr el interés compuesto

Este es el concepto de diseño central de la estrategia de posición rodante.

Problemas con las prácticas tradicionales:
Suponiendo que su cuenta de cambio tiene 1000 USDT:

  • La primera posición se abrió con 100 USDT.
  • Después de obtener una ganancia de 30 USDT, el saldo de la cuenta pasó a ser 1030 USDT.
  • ¿Cuánto debo utilizar para la segunda posición de apertura? ¿100 o 130?
  • ¿Cómo podemos distinguir si el beneficio proviene de la estrategia de posición continua o de otras operaciones?

Solución de agrupación de fondos:

// 创建一个虚拟的"策略资金池"
var strategyCapital = InitialCapital;  // 初始100 USDT

// 第1次交易
// 开仓金额 = 100 USDT
// 止盈后盈利 = 30 USDT
strategyCapital = strategyCapital + 30;  // 资金池变为130 USDT

// 第2次交易(滚仓)
var positionValue = strategyCapital * Leverage;  // 130 × 3 = 390
var amount = positionValue / price / ctVal;      // 计算开仓数量
// 自动使用了第1次的盈利,这就是复利的关键

// 止盈后盈利 = 39 USDT
strategyCapital = strategyCapital + 39;  // 资金池变为169 USDT

// 第3次交易(滚仓)
// 开仓金额 = 169 USDT(继续利滚利)

Las ventajas de este diseño:

  • Segregación de fondos:La estrategia solo utiliza los 100 USDT especificados y no afecta otros fondos en la cuenta.
  • Interés compuesto automático:Cada ganancia se agrega automáticamente al fondo de capital, por lo que se utilizará una cantidad mayor para la siguiente posición.
  • Los riesgos son controlables:El peor escenario es perder 100 USDT, lo cual está dentro de lo esperado.
  • Seguimiento claro:Puede señalar exactamente cuánto se renovó la estrategia desde 100 USDT.

3.3 Decisión de Rollover: ¿Continuar o detenerse después de tomar ganancias?

Este es el elemento central de la estrategia de posición continua:Después de ejecutar la orden de toma de ganancias, debemos tomar una decisión crucial: ¿continuar operando o detenernos?

Escenario de toma de decisiones:

假设我们做多BTC:
- 入场价:45000 USDT,用100 USDT开仓
- 止盈价:49500 USDT(涨10%)
- 止盈成交,盈利30 USDT
- 现在资金池:130 USDT

问题来了:
选项A:收手,带着130 USDT退出,回到空仓
选项B:继续,用130 USDT再次开多(滚仓)

¿Cómo elegir?

Esta decisión no puede basarse en “sentimientos”; debe haber estándares claros. Nuestra lógica de juicio es:¿Continúa la tendencia?

Método de juicio:
En el momento en que se ejecuta la orden de toma de ganancias, se recalculan los últimos indicadores técnicos (media móvil EMA):

// 止盈单成交后,获取最新K线数据
var records = _C(exchange.GetRecords, PERIOD_M1);
var emaFast = TA.EMA(records, FastEMA);
var emaSlow = TA.EMA(records, SlowEMA);

var ema5_current = emaFast[emaFast.length - 1];
var ema10_current = emaSlow[emaSlow.length - 1];

var shouldRoll = false;

if (currentDirection == "LONG") {
    // 多头止盈后,如果EMA5仍在EMA10上方,继续做多(滚仓)
    if (ema5_current > ema10_current) {
        shouldRoll = true;
        Log("✅ EMA5 > EMA10,上升趋势未破坏");
        Log("🔄 决策:继续做多(滚仓)");
    } else {
        Log("❌ EMA5 <= EMA10,趋势可能转弱");
        Log("⏸️ 决策:不滚仓,等待新信号");
    }
} else if (currentDirection == "SHORT") {
    // 空头止盈后,如果EMA5仍在EMA10下方,继续做空(滚仓)
    if (ema5_current < ema10_current) {
        shouldRoll = true;
        Log("✅ EMA5 < EMA10,下降趋势未破坏");
        Log("🔄 决策:继续做空(滚仓)");
    } else {
        Log("❌ EMA5 >= EMA10,趋势可能转弱");
        Log("⏸️ 决策:不滚仓,等待新信号");
    }
}

3.4 Proceso de ejecución de rollover

Si la decisión es “continuar renovando la posición”:

if (shouldRoll) {
    // 1. 增加滚仓计数
    currentRoundRolls++;
    
    Log("🔄 执行滚仓操作... (本轮第", currentRoundRolls, "次滚仓)");
    
    // 2. 获取最新价格
    var ticker = _C(exchange.GetTicker);
    var newPrice = ticker.Last;
    
    // 3. 基于新资金池重新开仓
    if (openPosition(currentDirection, newPrice)) {
        Log("✅ 滚仓成功!");
        // 4. 挂新的止盈单(在openPosition函数中完成)
        // 5. 设置新的止损价(在checkStopLoss函数中监控)
    } else {
        Log("❌ 滚仓失败,等待新信号");
        saveRollRecord(false);
        resetPositionState();
    }
}

Si la decisión es “stop”:

else {
    // 1. 保存本轮统计
    saveRollRecord(false);  // false表示正常结束,非止损
    
    // 2. 保留资金池金额
    // strategyCapital 保持当前值,等待下次机会
    
    // 3. 回到空仓状态
    resetPositionState();
    
    Log("⏳ 已平仓,等待新信号...");
}

Puntos claves de este proceso:

  • Emitir un juicio inmediatamente después de cada acción de toma de ganancias, sin demora.
  • Los criterios de juicio son objetivos (relación entre medias móviles), sin especulaciones subjetivas.
  • Continúa aumentando tu posición; detente y conserva tus ganancias.

3.5 El poder y el costo del interés compuesto

Experimentemos el poder del interés compuesto a través de un estudio de caso completo:

Historias de éxito:

初始资金:100 USDT
止盈比例:10%
杠杆:3倍

第1次:100 USDT → 盈利30 → 资金池130
第2次:130 USDT → 盈利39 → 资金池169
第3次:169 USDT → 盈利50.7 → 资金池219.7
第4次:219.7 USDT → 盈利65.9 → 资金池285.6
第5次:285.6 USDT → 盈利85.7 → 资金池371.3

连续滚5次,100变成371.3,增长271%!

Caso de fallo:

第1次:100 USDT → 盈利30 → 资金池130
第2次:130 USDT → 盈利39 → 资金池169
第3次:169 USDT → 趋势反转 → 触发止损
止损比例5%,亏损:169 × 3 × 5% = 25.35 USDT
剩余资金:169 - 25.35 = 143.65 USDT

原本从100滚到169,一次止损后只剩143.65

Esta es la espada de doble filo del trading de rollover:

  • En caso de éxito:El crecimiento exponencial es emocionante.
  • Cuando falla:Retroceso rápido, o incluso pérdidas.

IV. Pregunta 3: ¿Cuándo detenerse? — El stop loss es la última línea de defensa.

Mecanismo de detención de daños

4.1 Dos métodos de salida

Salida proactiva: debilitamiento de la tendencia
Esta situación ya se abordó en la “Pregunta Dos”: tras obtener ganancias, si la tendencia no favorece más ganancias, opte activamente por detenerse. Esta es la estrategia de salida ideal, dejando el mercado con ganancias.

Salida pasiva: activación del stop loss
En esto es en lo que nos centraremos ahora: cuando el mercado se mueve contra nosotros y el precio alcanza la línea de stop-loss, nos vemos obligados a cerrar nuestras posiciones.

4.2 La necesidad del stop loss

A muchas personas no les gustan las órdenes de stop loss porque:

  • Stop-loss significa admitir un error.
  • El stop loss provocará pérdidas reales.
  • A veces el precio rebota después de colocar una orden de stop loss.

Sin embargo, en la estrategia de posición rodante,El stop loss es el límite para la supervivencia.Piénsalo:

如果没有止损:
第1次:100 → 滚到 169
第2次:169 → 趋势反转,不止损
价格持续下跌:169 → 150 → 120 → 80 → 50...
最终可能全亏,甚至爆仓
如果有止损:
第1次:100 → 滚到 169
第2次:169 → 趋势反转,触发止损
止损5%:亏损 25.35
剩余:143.65
虽然亏了,但保留了大部分资金
可以等待下一个机会

La esencia del stop loss:Utilice pérdidas pequeñas y ciertas para evitar riesgos grandes e inciertos.

4.3 Implementación del código de stop-loss

// 检查止损
function checkStopLoss(currentPrice, position) {
    var totalDrawdown = 0;
    
    // 计算当前回撤
    if (currentDirection == "LONG") {
        totalDrawdown = (currentPrice - entryPrice) / entryPrice;
    } else {
        totalDrawdown = (entryPrice - currentPrice) / entryPrice;
    }
    
    // 判断是否触发止损
    if (totalDrawdown < -StopLossPercent) {
        Log("❌ 触发止损!回撤:", (totalDrawdown * 100).toFixed(2), "%");
        
        // 1. 取消止盈单
        if (takeProfitOrderId) {
            Log("取消止盈单:", takeProfitOrderId);
            exchange.CancelOrder(takeProfitOrderId);
            takeProfitOrderId = null;
            Sleep(500);
        }
        
        // 2. 市价平仓(循环重试直到成功)
        var profit = closePositionMarketWithRetry(currentPrice, position);
        
        // 3. 更新策略资金池
        strategyCapital += profit;  // profit是负数
        totalProfitRealized += profit;
        
        Log("止损亏损:", profit.toFixed(2), "U");
        Log("策略剩余资金:", strategyCapital.toFixed(2), "U");
        
        // 4. 记录本轮止损亏损
        currentRoundLoss = Math.abs(profit);
        Log("本轮止损亏损:", currentRoundLoss.toFixed(2), "U");
        
        // 5. 保存本轮滚仓记录(被止损中断)
        saveRollRecord(true);  // true表示止损结束
        
        // 6. 重置状态
        resetPositionState();
        
        // 7. 检查资金是否充足
        if (strategyCapital < 10) {
            Log("💥 策略资金不足10U,停止运行");
            throw "资金不足";
        }
        
        Log("⏳ 已止损,等待新信号...");
    }
}

4.4 Condiciones para la finalización del juego

¿Recuerdas el “Juego del Aventurero Racional” del que hablamos? Este juego tiene una condición final clara:

Condición 1: El fondo de capital se reduce a cero.

if (strategyCapital <= 0) {
    Log("💥 游戏结束:资金池已归零");
    Log("本次冒险失败,100 USDT全部亏光");
    throw "资金耗尽";
}

Condición 2: Retirada voluntaria

if (strategyCapital >= 目标金额) {
    Log("🎉 达到目标金额,可以选择主动退出");
    Log("锁定利润,开始新一轮100 USDT的游戏");
}

Condición 3: Alcanzar el número máximo de rollovers

if (连续滚仓次数 >= 10次) {
    Log("⚠️ 达到最大滚仓次数,主动退出");
    Log("持续时间太长,风险累积,见好就收");
    saveRollRecord(false);
    resetPositionState();
}

4.5 El equilibrio entre riesgo y rentabilidad

El núcleo de toda la estrategia de posición rotatoria está enEncontrar un equilibrio entre riesgo y rentabilidad

Lado de los ingresos:

  • Crecimiento compuesto: el fondo de capital aumenta después de cada acción de toma de ganancias.
  • Captura de tendencias: Obtener ganancias consistentemente en tendencias alcistas y bajistas
  • Sin límite superior: teóricamente, puede continuar indefinidamente.

Lado del riesgo:

  • Protección stop loss: pérdida máxima del 5% del capital en una sola transacción.
  • Segregación de fondos: pérdida máxima de 100 USDT
  • Análisis de tendencias: evite las órdenes de stop loss frecuentes en un mercado volátil.

V. Backtesting práctico: Análisis del caso TRUMP_USDT

TRUMP_USDTAnálisis retrospectivo del primer día de cotización de Binance Futures (del 20 al 21 de enero de 2025):

Prueba retrospectiva de la curva de acciones

Tabla de estadísticas de rollover

Los resultados del backtest muestran que:

Reflejos:

  • La estrategia capturó con éxito las dramáticas fluctuaciones de los primeros días de Trump después de su salida a bolsa.
  • A través de múltiples refinanciaciones se logró un rápido crecimiento de los fondos.
  • El mecanismo de toma de ganancias fija efectivamente las ganancias dentro de una tendencia.

Exposición a riesgos:

  • Cuando la tendencia se revierte, las órdenes de stop loss hacen que se devuelvan algunas ganancias.
  • Apareció una falsa señal de ruptura en el mercado volátil.
  • El riesgo de concentración es mayor con una moneda única

Datos clave:

  • Número total de reinversiones: X veces
  • Rollover máximo en una sola ronda: X veces
  • Caída máxima: X%
  • Tasa de rendimiento final: X%

VI. La naturaleza y las limitaciones de la estrategia

6.1 ¿Qué simula esta estrategia?

A través del análisis anterior, podemos ver claramente que esta estrategia es esencialmente una simulación:

El comportamiento comercial de un aventurero racional:

  • Hay reglas de entrada claras (no trading impulsivo).
  • Establecer un objetivo de ganancias (evitar la codicia).
  • Tenga disciplina para detener los pérdidas (no se aferre a posiciones perdedoras).
  • Tiene la capacidad de tomar decisiones sobre posiciones continuas (y utilizar ganancias).
  • Existen restricciones de financiación (para controlar el riesgo).

Su lógica central es:

  1. Reserva una cantidad fija de capital (100 USDT) para probarlo.
  2. Gana dinero siguiendo las tendencias.
  3. Después de ganar dinero, utilice las ganancias para continuar operando (composición de ganancias).
  4. Si la tendencia se debilita, deténgase inmediatamente.
  5. Si el juicio es erróneo, corte sus pérdidas rápidamente.
  6. Hasta que los fondos se agoten o se transfieran a un monto satisfactorio.

6.2 Limitaciones de la estrategia

Limitación 1: Dependencia de los mercados de tendencia
Esta estrategia funciona mal en mercados volátiles porque:

  • Falsas fugas frecuentes
  • El precio retrocedió después de que tomé ganancias, por lo que no pude renovar la posición.
  • Las órdenes de stop loss repetidas agotan el fondo de capital.

Limitación 2: Sensibilidad de los parámetros
Parámetros como un objetivo de beneficio del 10% y un stop loss del 5% no son óptimos:

  • Diferentes monedas tienen diferente volatilidad
  • Diferentes condiciones de mercado requieren diferentes parámetros
  • Los parámetros fijos son difíciles de adaptar a todas las situaciones.

Limitación 3: Punto de detonación impredecible
Como se mencionó anteriormente, el uso de indicadores técnicos para ingresar al mercado es esencialmente una apuesta:

  • Podrías perderte los grandes movimientos reales del mercado.
  • Entrar durante una falsa ruptura
  • Incapaz de planificar con anticipación como los que están dentro del sistema

6.3 Áreas de mejora

Opción 1: Filtrar monedas según el flujo de trabajo

  • No escojas cualquier criptomoneda y te vayas.
  • En cambio, el flujo de trabajo se utiliza para filtrar primero las criptomonedas populares y de alto potencial.
  • Por ejemplo: un aumento en las discusiones en las redes sociales, un volumen de transacciones anormal y datos activos en cadena.
  • El uso de una estrategia de posiciones continuas en estas criptomonedas dará como resultado una mayor tasa de éxito.

Dirección 2: Ajustar dinámicamente los parámetros

  • Ajuste los ratios de toma de ganancias y stop loss en función de la volatilidad histórica de la moneda.
  • Para monedas altamente volátiles, amplíe adecuadamente el rango de stop-loss.
  • Para las criptomonedas con baja volatilidad, puedes reducir tu objetivo de ganancias.

Dirección 3: Múltiples fondos de inversión que operan en paralelo

  • No se trata de poner 100 USDT en una moneda.
  • En lugar de ello, se divide en cinco cantidades de 20 USDT, que se transfieren simultáneamente en cinco criptomonedas potenciales.
  • Diversifique el riesgo y aumente la probabilidad de “ganar el premio gordo”.

Conclusión

A través de la deducción de tres preguntas fundamentales, hemos demostrado plenamente cómo traducir la idea de trading de renovar posiciones a la lógica del código. La esencia de este proceso es:Expresar la mentalidad comercial de un tomador de riesgos racional utilizando reglas y estructuras de datos precisas.

Nota importante:

Esto es solo una simulación de la estrategia de rotación de posiciones. En realidad, la rotación de posiciones es una estrategia de trading que requiere mucha experiencia en el mercado. Esta estrategia es solo una herramienta. Posteriormente, puede combinarse con flujos de trabajo para identificar criptomonedas populares o con gran potencial. Usar esta herramienta nos traerá más sorpresas.

Recuerda:

  • La pérdida máxima es 100 USDT y el riesgo es manejable.
  • Si tiene la suerte de captar una tendencia importante, su inversión podría multiplicarse varias veces o incluso decenas de veces.
  • Pero la mayoría de las veces, puede implicar pequeñas ganancias y pérdidas y pruebas repetidas.
  • Este es un juego que requiere paciencia y disciplina.

No existe ninguna estrategia que garantice ganancias.La renovación de posiciones es solo una herramienta. Lo que realmente determina el éxito o el fracaso es tu capacidad para:

  • Identificar criptomonedas prometedoras (utilizando el filtrado de flujo de trabajo).
  • Apéguese a las órdenes de stop loss (no se aferre obstinadamente).
  • Sea lo suficientemente audaz para renovar sus posiciones cuando surja una tendencia importante (no salga demasiado pronto).
  • Manténgase racional (no deje que sus emociones lo controlen).

¡Espero que todos ustedes encuentren su propia “gran suerte” en su viaje hacia el trading cuantitativo!

Dirección completa de la póliza:**Código fuente de la estrategia -> ** https://www.fmz.com/strategy/521864

Código de estrategia completo:

”`js /*backtest start: 2025-01-20 00:00:00 end: 2025-01-21 00:00:00 period: 1m basePeriod: 1m exchanges: [{“eid”:“Futures_Binance”,“currency”:“TRUMP_USDT”,“balance”:5000}] */

// ============================================ // 滚仓策略 - EMA5/EMA10 简化版 // 使用 CreateOrder 统一下单 // 持续检测订单状态 // 止盈后根据EMA关系决定是否滚仓 // 新增:滚仓统计功能(三个两行表格) // 修复:方向记录、亏损记录、入场价格记录 // 优化:市价平仓循环重试直到成功 // 优化:滚仓统计表格新增开始/结束时间 // ============================================

// ========== 策略参数(可调整)========== var Symbol = “TRUMP_USDT.swap”; // 交易币种 var InitialCapital = 100; // 策略初始资金 100U var Leverage = 3; // 杠杆倍数 var RollProfitPercent = 0.10; // 滚仓盈利系数(10% = 0.10) var StopLossPercent = 0.05; // 止损系数(10% = 0.10)

// EMA参数 var FastEMA = 5; var SlowEMA = 10;

// 全局变量 var strategyCapital = InitialCapital; var entryPrice = 0; var lastRollPrice = 0; var rollCount = 0; var totalProfitRealized = 0; var currentDirection = “”; var takeProfitOrderId = null; // 止盈单ID var amountPrecision = 0; // 数量精度 var pricePrecision = 2; // 价格精度 var ctVal = 1; // 合约面值

// ========== 滚仓统计变量 ========== var currentRoundRolls = 0; // 本轮滚仓次数(连续滚仓) var currentRoundStartTime = 0; // 本轮开始时间 var currentRoundDirection = “”; // 本轮方向 var currentRoundTotalProfit = 0; // 本轮累计盈利(每次止盈累加) var currentRoundLoss = 0; // 本轮亏损(止损时记录) var currentRoundEntryPrice = 0; // 本轮入场价格 var rollHistory = []; // 滚仓历史记录 var maxHistoryRecords = 10; // 保留最近10次滚仓记录

function main() { Log(“=== EMA滚仓策略启动(CreateOrder模式 + 滚仓统计)===”); Log(“交易币种:”, Symbol); Log(“━━━━━━━━━━━━━━━━━━━━”);

// 获取市场信息
var markets = exchange.GetMarkets();
if (!markets || !markets[Symbol]) {
    Log("❌ 错误:无法获取", Symbol, "的市场信息");
    return;
}

var marketInfo = markets[Symbol];
amountPrecision = marketInfo.AmountPrecision;
pricePrecision = marketInfo.PricePrecision || 2;
ctVal = marketInfo.CtVal;

Log("市场信息:");
Log("  - 数量精度:", amountPrecision);
Log("  - 价格精度:", pricePrecision);
Log("  - 合约面值:", ctVal);

var account = _C(exchange.GetAccount);
Log("账户总资金:", account.Balance.toFixed(2), "U");
Log("策略使用资金:", InitialCapital, "U");
Log("杠杆倍数:", Leverage, "倍");
Log("滚仓系数:", (RollProfitPercent * 100), "%");
Log("止损系数:", (StopLossPercent * 100), "%");
Log("━━━━━━━━━━━━━━━━━━━━");

if (account.Balance < InitialCapital) {
    Log("❌ 错误:账户余额不足");
    return;
}

exchange.SetContractType("swap");
exchange.SetMarginLevel(Leverage);

var lastBarTime = 0;

while (true) {

    var records = _C(exchange.GetRecords, PERIOD_M1);

    if (records.length < SlowEMA + 5) {
        Sleep(3000);
        continue;
    }

    var currentBarTime = records[records.length - 1].Time;
    if (currentBarTime == lastBarTime) {
        Sleep(1000);
        continue;
    }
    lastBarTime = currentBarTime;

    var ticker = _C(exchange.GetTicker);
    var currentPrice = ticker.Last;
    var account = _C(exchange.GetAccount);
    var position = _C(exchange.GetPositions); 

    // 计算EMA
    var emaFast = TA.EMA(records, FastEMA);
    var emaSlow = TA.EMA(records, SlowEMA);

    if (emaFast.length < 3 || emaSlow.length < 3) {
        Sleep(3000);
        continue;
    }

    var ema5_current = emaFast[emaFast.length - 1];
    var ema5_prev = emaFast[emaFast.length - 2];
    var ema10_current = emaSlow[emaSlow.length - 1];
    var ema10_prev = emaSlow[emaSlow.length - 2];

    var isBullTrend = ema5_current > ema10_current;
    var isBearTrend = ema5_current < ema10_current;

    var bullCross = ema5_prev <= ema10_prev && ema5_current > ema10_current;
    var bearCross = ema5_prev >= ema10_prev && ema5_current < ema10_current;

    if(takeProfitOrderId){
        checkTakeProfitOrder();
    }

    // ========== 持仓逻辑 ==========
    if (position.length > 0) {
        var pos = position[0];
        currentDirection = pos.Type == PD_LONG ? "LONG" : "SHORT";

        if (entryPrice == 0) {
            entryPrice = pos.Price;
            lastRollPrice = pos.Price;
        }

        // 检查止损
        checkStopLoss(currentPrice, pos);

    } else {
        // ========== 空仓:等待信号 ==========
        if (bullCross) {
            Log("📈 金叉信号 - 做多");
            openPosition("LONG", currentPrice);
        } else if (bearCross) {
            Log("📉 死叉信号 - 做空");
            openPosition("SHORT", currentPrice);
        }
    }

    showStatus(account, position, currentPrice, ema5_current, ema10_current, isBullTrend, currentBarTime);

    Sleep(1000);
}

}

// 开仓(持续检测订单状态) function openPosition(direction, price) { Log(“🚀 开仓”, direction == “LONG” ? “做多” : “做空”); Log(“使用资金:”, strategyCapital.toFixed(2), “U”);

var positionValue = strategyCapital * Leverage;
var amount = _N(positionValue / price / ctVal, amountPrecision);

Log("计算数量:", amount, "| 持仓价值:", positionValue.toFixed(2), "U");

if (amount <= 0) {
    Log("❌ 数量无效");
    return false;
}

// 使用 CreateOrder 市价开仓
var orderId = exchange.CreateOrder(Symbol, direction == "LONG" ? "buy" : "sell", -1, amount);

if (!orderId) {
    Log("❌ 下单失败");
    return false;
}

Log("订单ID:", orderId, "开始持续检测...");

// 持续检测订单状态,直到成交或超时
var maxWaitTime = 30000;  // 最多等待30秒
var startTime = Date.now();
var checkCount = 0;

while (Date.now() - startTime < maxWaitTime) {
    Sleep(500);
    checkCount++;

    var order = exchange.GetOrder(orderId);
    if (!order) {
        Log("❌ 无法获取订单信息");
        continue;
    }

    if (order.Status == 1) {
        // 订单已成交
        var avgPrice = order.AvgPrice;
        entryPrice = avgPrice;
        lastRollPrice = avgPrice;
        currentDirection = direction;

        // ========== 修改:无论是否第一次,都要初始化/更新统计数据 ==========
        if (currentRoundRolls == 0) {
            // 第一次开仓:初始化所有统计数据
            currentRoundStartTime = Date.now();
            currentRoundDirection = direction;
            currentRoundTotalProfit = 0;
            currentRoundLoss = 0;
            currentRoundEntryPrice = avgPrice;
            Log("🆕 开始新一轮交易统计");
            Log("  - 开始时间:", _D(currentRoundStartTime));
            Log("  - 方向:", direction == "LONG" ? "🟢 多头" : "🔴 空头");
            Log("  - 入场价格:", avgPrice.toFixed(pricePrecision));
        } else {
            // 滚仓时:更新方向(理论上应该相同,但为了健壮性还是更新)
            currentRoundDirection = direction;
            Log("🔄 滚仓操作 (第", currentRoundRolls, "次)");
            Log("  - 方向:", direction == "LONG" ? "🟢 多头" : "🔴 空头");
            Log("  - 入场价格:", avgPrice.toFixed(pricePrecision));
        }

        Log("✅ 开仓成功!");
        Log("  - 成交均价:", avgPrice.toFixed(pricePrecision));
        Log("  - 成交数量:", order.DealAmount);
        Log("  - 成交金额:", (order.DealAmount * avgPrice * ctVal).toFixed(2), "U");

        // 挂止盈单
        Sleep(1000);
        placeTakeProfitOrder(direction, avgPrice, order.DealAmount);

        return true;
    } else if (order.Status == 2) {
        // 订单已取消
        Log("❌ 订单已取消");
        return false;
    }
    // Status == 0 表示未成交,继续等待
}

// 超时未成交
Log("⚠️ 订单超时,尝试取消订单");
exchange.CancelOrder(orderId);
return false;

}

// 挂止盈单 function placeTakeProfitOrder(direction, entryPrice, amount) { var takeProfitPrice = 0;

if (direction == "LONG") {
    takeProfitPrice = _N(entryPrice * 1.1, pricePrecision);  // 多头止盈:+10%
} else {
    takeProfitPrice = _N(entryPrice * 0.9, pricePrecision);  // 空头止盈:-10%
}

Log("📌 挂止盈单");
Log("  - 入场价格:", entryPrice.toFixed(pricePrecision));
Log("  - 止盈价格:", takeProfitPrice);
Log("  - 数量:", amount);

// 使用 CreateOrder 挂限价止盈单
if (direction == "LONG") {
    takeProfitOrderId = exchange.CreateOrder(Symbol, "closebuy", takeProfitPrice, amount);
} else {
    takeProfitOrderId = exchange.CreateOrder(Symbol, "closesell", takeProfitPrice, amount);
}

if (takeProfitOrderId) {
    Log("✅ 止盈单已挂,订单ID:", takeProfitOrderId);
} else {
    Log("❌ 止盈单挂单失败");
}

}

// 检查止盈单状态 function checkTakeProfitOrder() {

if (!takeProfitOrderId) {
    return;
}

var order = exchange.GetOrder(takeProfitOrderId);
if (!order) {
    return;
}

if (order.Status == 1) {
    // 止盈单成交
    Log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    Log("💰 止盈单成交!");
    Log("  - 成交价格:", order.AvgPrice.toFixed(pricePrecision));
    Log("  - 成交数量:", order.DealAmount);

    // 使用订单数据精确计算盈利
    var profit = 0;
    if (currentDirection == "LONG") {
        // 多头盈利 = (止盈价 - 入场价) * 数量 * 合约面值
        profit = (order.AvgPrice - entryPrice) * order.DealAmount * ctVal;
    } else {
        // 空头盈利 = (入场价 - 止盈价) * 数量 * 合约面值
        profit = (entryPrice - order.AvgPrice) * order.DealAmount * ctVal;
    }

    // 计算盈利率
    var profitRate = profit / strategyCapital;

    Log("📊 盈利统计:");
    Log("  - 入场价格:", entryPrice.toFixed(pricePrecision));
    Log("  - 止盈价格:", order.AvgPrice.toFixed(pricePrecision));
    Log("  - 本次盈利:", profit.toFixed(2), "U");
    Log("  - 盈利率:", (profitRate * 100).toFixed(2), "%");
    Log("  - 策略资金(盈利前):", strategyCapital.toFixed(2), "U");

    // 更新资金
    strategyCapital += profit;
    totalProfitRealized += profit;
    rollCount++;

    Log("  - 策略资金(盈利后):", strategyCapital.toFixed(2), "U");
    Log("  - 累计盈利:", totalProfitRealized.toFixed(2), "U");
    Log("  - 滚仓次数:", rollCount, "次");

    // ========== 累加本轮盈利 ==========
    currentRoundTotalProfit += profit;
    Log("  - 本轮累计盈利:", currentRoundTotalProfit.toFixed(2), "U");

    // 重置止盈单ID
    takeProfitOrderId = null;

    // 获取最新K线计算EMA
    Sleep(1000);
    var records = _C(exchange.GetRecords, PERIOD_M1);
    var emaFast = TA.EMA(records, FastEMA);
    var emaSlow = TA.EMA(records, SlowEMA);

    if (emaFast.length < 2 || emaSlow.length < 2) {
        Log("⚠️ EMA数据不足,无法判断是否滚仓");

        // 记录本轮滚仓结束(正常结束,之前有盈利)
        saveRollRecord(false);

        resetPositionState();
        Log("⏳ 等待新信号...");
        Log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        return;
    }

    var ema5_current = emaFast[emaFast.length - 1];
    var ema10_current = emaSlow[emaSlow.length - 1];

    Log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    Log("📈 EMA滚仓判断:");
    Log("  - EMA5:", ema5_current.toFixed(pricePrecision));
    Log("  - EMA10:", ema10_current.toFixed(pricePrecision));
    Log("  - 原持仓方向:", currentDirection);

    var shouldRoll = false;

    if (currentDirection == "LONG") {
        // 多头止盈后,如果EMA5仍在EMA10上方,继续做多(滚仓)
        if (ema5_current > ema10_current) {
            shouldRoll = true;
            Log("  - 判断结果: ✅ EMA5 > EMA10,趋势延续");
            Log("  - 决策: 🔄 继续做多(滚仓)");
        } else {
            Log("  - 判断结果: ❌ EMA5 <= EMA10,趋势转弱");
            Log("  - 决策: ⏸️ 不滚仓,等待新信号");
        }
    } else if (currentDirection == "SHORT") {
        // 空头止盈后,如果EMA5仍在EMA10下方,继续做空(滚仓)
        if (ema5_current < ema10_current) {
            shouldRoll = true;
            Log("  - 判断结果: ✅ EMA5 < EMA10,趋势延续");
            Log("  - 决策: 🔄 继续做空(滚仓)");
        } else {
            Log("  - 判断结果: ❌ EMA5 >= EMA10,趋势转弱");
            Log("  - 决策: ⏸️ 不滚仓,等待新信号");
        }
    }

    Log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");

    if (shouldRoll) {
        // ========== 滚仓:增加本轮滚仓次数 ==========
        currentRoundRolls++;
        Log("🔄 执行滚仓操作... (本轮第", currentRoundRolls, "次滚仓)");
        Sleep(1000);

        var ticker = _C(exchange.GetTicker);
        var newPrice = ticker.Last;

        if (openPosition(currentDirection, newPrice)) {
            Log("✅ 滚仓成功!");
        } else {
            Log("❌ 滚仓失败,等待新信号");
            // 记录本轮滚仓结束(滚仓失败,但之前有盈利)
            saveRollRecord(false);
            resetPositionState();
        }
    } else {
        // ========== 不滚仓:记录本轮滚仓结束 ==========
        saveRollRecord(false);
        resetPositionState();
        Log("⏳ 已平仓,等待新信号...");
    }

    Log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
}

}

// ========== 保存滚仓记录 ========== function saveRollRecord(isStopLoss) { // 必须有开始时间才记录(防止异常情况) if (currentRoundStartTime == 0) { Log(“⚠️ 本轮未正确初始化,跳过记录”); currentRoundRolls = 0; currentRoundTotalProfit = 0; currentRoundLoss = 0; currentRoundDirection = “”; currentRoundEntryPrice = 0; return; }

var endTime = Date.now();
var duration = endTime - currentRoundStartTime;

// 计算总体盈利 = 累计盈利 - 亏损
var netProfit = currentRoundTotalProfit - currentRoundLoss;

var record = {
    direction: currentRoundDirection,      // 本轮方向
    roundRolls: currentRoundRolls,        // 本轮滚仓次数
    totalProfit: currentRoundTotalProfit, // 累计盈利(止盈累加)
    loss: currentRoundLoss,               // 亏损金额(止损)
    netProfit: netProfit,                 // 总体盈利
    duration: duration,                   // 持续时间(毫秒)
    isStopLoss: isStopLoss,              // 是否止损结束
    startTime: currentRoundStartTime,     // 开始时间
    endTime: endTime,                     // 结束时间
    entryPrice: currentRoundEntryPrice    // 入场价格
};

rollHistory.push(record);

// 只保留最近N条记录
if (rollHistory.length > maxHistoryRecords) {
    rollHistory.shift();
}

Log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Log("📝 保存滚仓记录:");
Log("  - 方向:", currentRoundDirection == "LONG" ? "🟢 多头" : "🔴 空头");
Log("  - 入场价格:", currentRoundEntryPrice.toFixed(pricePrecision));
Log("  - 开始时间:", _D(currentRoundStartTime));
Log("  - 结束时间:", _D(endTime));
Log("  - 持续时间:", formatDuration(duration));
Log("  - 本轮滚仓次数:", currentRoundRolls);
Log("  - 累计盈利:", currentRoundTotalProfit.toFixed(2), "U");
Log("  - 亏损金额:", currentRoundLoss.toFixed(2), "U");
Log("  - 总体盈利:", netProfit.toFixed(2), "U");
Log("  - 结束方式:", isStopLoss ? "❌ 止损" : "✅ 正常");
Log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");

// 重置本轮统计数据
currentRoundRolls = 0;
currentRoundStartTime = 0;
currentRoundDirection = "";
currentRoundTotalProfit = 0;
currentRoundLoss = 0;
currentRoundEntryPrice = 0;

}

// 格式化时长 function formatDuration(ms) { var seconds = Math.floor(ms / 1000); var minutes = Math.floor(seconds / 60); var hours = Math.floor(minutes / 60); var days = Math.floor(hours / 24);

if (days > 0) {
    return days + "天" + (hours % 24) + "时" + (minutes % 60) + "分";
} else if (hours > 0) {
    return hours + "时" + (minutes % 60) + "分";
} else if (minutes > 0) {
    return minutes + "分" + (seconds % 60) + "秒";
} else {
    return seconds + "秒";
}

}

// 重置持仓状态函数 function resetPositionState() { entryPrice = 0; lastRollPrice = 0; currentDirection = “”; // 注意:不重置 rollCount、strategyCapital 和 currentRoundRolls }

// 检查止损 function checkStopLoss(currentPrice, position) { var totalDrawdown = 0;

if (currentDirection == "LONG") {
    totalDrawdown = (currentPrice - entryPrice) / entryPrice;
} else {
    totalDrawdown = (entryPrice - currentPrice) / entryPrice;
}

if (totalDrawdown < -StopLossPercent) {
    Log("❌ 触发止损!回撤:", (totalDrawdown * 100).toFixed(2), "%");

    // 取消止盈单
    if (takeProfitOrderId) {
        Log("取消止盈单:", takeProfitOrderId);
        exchange.CancelOrder(takeProfitOrderId);
        takeProfitOrderId = null;
        Sleep(500);
    }

    // ========== 市价平仓(循环重试直到成功) ==========
    var profit = closePositionMarketWithRetry(currentPrice, position);

    // 更新策略资金池
    strategyCapital += profit;
    totalProfitRealized += profit;

    Log("止损亏损:", profit.toFixed(2), "U");
    Log("策略剩余资金:", strategyCapital.toFixed(2), "U");
    Log("累计盈利:", totalProfitRealized.toFixed(2), "U");

    // ========== 记录本轮止损亏损 ==========
    currentRoundLoss = Math.abs(profit);  // 转为正数保存
    Log("本轮止损亏损:", currentRoundLoss.toFixed(2), "U");

    // ========== 记录本轮滚仓结束(被止损中断) ==========
    saveRollRecord(true);

    // 重置状态
    resetPositionState();

    if (strategyCapital < 10) {
        Log("💥 策略资金不足10U,停止运行");
        throw "资金不足";
    }

    Log("⏳ 已止损,等待新信号...");
}

}

// ========== 市价平仓(带重试机制,直到成功) ========== function closePositionMarketWithRetry(currentPrice, position) { Log(“🔴 市价平仓(循环重试模式)”);

var maxRetries = 10;  // 最多重试10次
var retryCount = 0;

while (retryCount < maxRetries) {
    retryCount++;
    Log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    Log("🔄 第", retryCount, "次平仓尝试");

    var profit = closePositionMarket(currentPrice, position);

    // 如果返回值不为0,说明平仓成功
    if (profit !== 0) {
        Log("✅ 平仓成功!");
        Log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        return profit;
    }

    // 平仓失败,检查持仓是否还存在
    Sleep(2000);
    var newPosition = _C(exchange.GetPosition);

    if (newPosition.length == 0) {
        Log("⚠️ 持仓已不存在,可能已被其他途径平仓");
        Log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        return 0;
    }

    // 更新position和currentPrice
    position = newPosition[0];
    var ticker = _C(exchange.GetTicker);
    currentPrice = ticker.Last;

    Log("⚠️ 平仓失败,", (maxRetries - retryCount), "次重试机会剩余");
    Log("等待3秒后重试...");
    Sleep(3000);
}

// 所有重试都失败
Log("❌ 平仓失败!已达到最大重试次数");
Log("⚠️ 请手动检查持仓状态!");
Log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
return 0;

}

// 市价平仓(持续检测订单状态) function closePositionMarket(currentPrice, position) { Log(“📤 发起市价平仓订单”);

var pos = position;
var amount = pos.Amount;

if (pos.Type == PD_LONG) {
    exchange.SetDirection("closebuy");
} else {
    exchange.SetDirection("closesell");
}

// 市价平仓
var orderType = pos.Type == PD_LONG ? "closebuy" : "closesell";
var orderId = exchange.CreateOrder(Symbol, orderType, -1, amount);

if (!orderId) {
    Log("❌ 平仓下单失败");
    return 0;
}

Log("平仓订单ID:", orderId, "开始持续检测...");

// 持续检测订单状态
var maxWaitTime = 30000;  // 单次等待最多30秒
var startTime = Date.now();
var checkCount = 0;

while (Date.now() - startTime < maxWaitTime) {
    Sleep(500);
    checkCount++;

    var order = exchange.GetOrder(orderId);
    if (!order) {
        Log("❌ 无法获取订单信息(检测", checkCount, "次)");
        continue;
    }

    if (order.Status == 1) {
        // 平仓成功
        Log("✅ 订单成交,成交价:", order.AvgPrice.toFixed(pricePrecision));
        var profit = calculateProfit(pos, order.AvgPrice);
        Log("盈亏:", profit.toFixed(2), "U");
        return profit;
    } else if (order.Status == 2) {
        Log("❌ 平仓订单已被取消");
        return 0;
    }

    // Status == 0 表示未成交,继续等