Type/to search
2
Follow
497
Followers
Jogo dos Aventureiros: Implementação de Código e Aplicação da Estratégia de Rolagem
Discussions
Created 2025-12-19 17:06:01  Updated 2025-12-29 09:04:46
 0
 733

img

introdução

No campo do trading quantitativo, a estratégia de posições rotativas é um tópico atraente, porém desafiador. A ideia central dessa estratégia é alcançar crescimento composto reinvestindo os lucros realizados em mercados em tendência. Este artigo irá explorar como traduzir essa ideia de trading em lógica de código executável, passo a passo, com foco na mudança de mentalidade em vez de detalhes técnicos. É importante ressaltar que, embora a estratégia de posições rotativas amplifique os retornos, ela também amplifica os riscos; este artigo tem fins meramente educativos e de discussão.


I. Análise detalhada da lógica de lucro da estratégia de posição rolante

1.1 A Essência Matemática da Rolagem

Diagrama de capotamento

A lógica de lucro da estratégia de posição rolante é essencialmente umaModelo de crescimento compostoVamos entender isso usando um exemplo simplificado:

Negociação única tradicional (3 aumentos consecutivos de 10% cada):

  • Capital inicial: 100 USDT, alavancagem de 3x
  • Aumento de mercado: (1+10%) × (1+10%) × (1+10%) - 1 = 33,1%
  • Lucro: 100 × 3 × 33,1% = 99,3 USDT
  • Preço final: 199,3 USDT

Operações de rolagem (três operações consecutivas, cada uma com aumento de 10%):

  • primeira vez100 USDT → Lucro de 30 USDT → Fundos passam a ser 130 USDT
    • Cálculo: 100 × 3x alavancagem × aumento de 10% = 30
  • 2ª vez130 USDT → Lucro de 39 USDT → Fundos passam a ser 169 USDT
    • Cálculo: 130 × 3x alavancagem × aumento de 10% = 39
  • 169 USDT → Lucro de 50,7 USDT → Fundos aumentaram para 219,7 USDT
    • Cálculo: 169 × 3x alavancagem × aumento de 10% = 50,7

Resultados da comparação:

No mesmo cenário em que o mercado sobe 10% três vezes seguidas:

  • transação únicaLucro de 99,3 USDT
  • Negociação de rolagemLucro de 119,7 USDT
  • Vantagens dos juros compostos20,4 USDT (um aumento de aproximadamente 20,5%)

Da mesma forma, com três aumentos consecutivos de 10% cada vez, o lucro para uma única negociação foi de 99,3 USDT e o lucro ao rolar a posição foi de 119,7 USDT.Essa diferença é o poder dos juros compostos.

Expressando isso por meio de uma fórmula matemática:

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

Isso revela a essência do rollover:**Transformando o crescimento linear em crescimento exponencial.**No entanto, isso também expôs riscos:Uma única ordem de stop-loss poderia anular todos os ganhos compostos anteriores.

1.2 Três questões centrais da estratégia de rollover

Antes de começarmos a escrever qualquer código, precisamos responder a três perguntas fundamentais de uma perspectiva estratégica:

Pergunta 1: Quando começa? (Primeira entrada)
É necessário determinar o sinal inicial de uma tendência.

Pergunta 2: Quando continuar? (Posição de rolamento adicional)
Este é o ponto crucial da rolagem de posições: como determinar se a tendência continuará após a realização dos lucros.

Pergunta 3: Quando parar? (Retirar-se e observar)

  • Saída proativa: tendência de enfraquecimento
  • Saída passiva: acionamento do stop loss

Essas três questões determinam a estrutura de toda a estratégia, e agora vamos traduzi-las em lógica de código uma a uma.


II. Pergunta 1: Quando começar? — Encontrando o ponto de inflexão para a entrada.

Sinais de entrada

2.1 O Ideal e a Realidade da Estratégia de Rollover

Vamos primeiro entender o cenário de aplicação ideal para a estratégia de rolagem de posições.

Cenário ideal:
Imagine se você pudesse entrar no mercado SHIB quando ele começasse a subir a partir de US$ 0,000001, ou estabelecer uma posição pouco antes de uma determinada altcoin sofrer uma alta. Através do rollover contínuo, 100 USDT poderiam potencialmente se tornar 10.000 USDT ou até mais. Este é o sonho final da estratégia de rollover.Entre no mercado antes que a criptomoeda exploda e obtenha retornos dez vezes maiores ou até cem vezes maiores.

A dura realidade:
O problema é: como saber qual criptomoeda terá uma alta expressiva? E quando essa alta ocorrerá?

  • Se você é proprietário do projeto ou está envolvido com a empresa, pode ter conhecimento prévio de notícias positivas.
  • Se você é um trader regular, só pode tomar decisões com base em sinais de mercado.

Para a maioria de nós, capturar com precisão esse ponto de inflexão é...**Resumindo, tudo se resume à sorte.**Não podemos prever o futuro; podemos apenas tentar aumentar a probabilidade de "ganhar na loteria" usando dados históricos e indicadores técnicos.

2.2 Do Ideal à Realidade: Simulação de Entrada Baseada em Indicadores Técnicos

Como não podemos prever qual criptomoeda terá um aumento significativo de valor, tudo o que podemos fazer é:Estabeleça um conjunto executável de regras de entrada e utilize indicadores técnicos para simular sinais de "início de tendência".

É como pescar no vasto oceano. Mesmo sem saber onde estão os peixes grandes, podemos:

  • Observe as ondulações na superfície da água (flutuações de preço).
  • Analise a direção do fluxo de água (direção da tendência).
  • Escolha as ferramentas apropriadas (indicadores técnicos)

Quando vários sinais convergem, acreditamos que uma tendência pode estar prestes a começar, então entramos no mercado para testá-la. Se estivermos certos, seguimos a tendência e rolamos nossas posições para ganhar dinheiro; se estivermos errados, limitamos nossas perdas e saímos do mercado imediatamente.

2.3 Implementação Técnica do Sinal de Entrada

Escolhendo ferramentas técnicas:
Utilizamos o sistema de médias móveis exponenciais (EMA5 e EMA10) como ferramenta de identificação de tendências. A razão para essa escolha é simples:

  • Simples, intuitivo e fácil de verificar.
  • Capacidade de reagir rapidamente às mudanças de preço.
  • Os parâmetros equilibram sensibilidade e estabilidade.

Lógica principal:
Ao detectar a "cruz de ouro" (EMA5 cruzando acima da EMA10) e a "cruz da morte" (EMA5 cruzando abaixo da EMA10) das médias móveis, é possível identificar pontos de reversão de tendência:

  • Cruz dourada → Sinal de compra
  • Cruz da morte → Sinal de venda a descoberto

A ideia do código:

javascript
// 计算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 seção não abordará os detalhes das cruzes douradas e das cruzes da morte; esses são conceitos fundamentais no mercado financeiro. O ponto principal é:Precisamos de um sinal de entrada claro e quantificável para acionar o início da rolagem.


III. Pergunta 2: Quando continuar? — O mecanismo central dos juros compostos.

Mecanismo de capotamento

3.1 Compreendendo a essência da rolagem: Um jogo de aventureiro racional

A estratégia de rollover é essencialmenteUm jogo de aventura racionalVamos entender isso usando um cenário completo:

Regras do jogo:

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

A genialidade deste jogo reside em:

  • O risco é administrável: a perda máxima é de 100 USDT, o que não afetará outros fundos na conta.
  • Lucros ilimitados: Se a tendência estiver a seu favor, os juros compostos podem dobrar seu capital rapidamente.
  • Regras bem definidas para entrada e saída: regras claras para realizar lucros, limitar perdas e renovar posições.

3.2 Estrutura do Fundo de Capital: A Chave para Alcançar Juros Compostos

Este é o conceito central do projeto da estratégia de posicionamento rotativo.

Problemas com as práticas tradicionais:
Supondo que sua conta na corretora tenha 1000 USDT:

  • A primeira posição foi aberta com 100 USDT.
  • Após obter um lucro de 30 USDT, o saldo da conta passou a ser de 1030 USDT.
  • Quanto devo usar na segunda posição de abertura? 100 ou 130?
  • Como podemos distinguir se o lucro provém da estratégia de rolagem de posições ou de outras operações?

Solução de angariação de fundos:

javascript
// 创建一个虚拟的"策略资金池" 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(继续利滚利)

As vantagens deste projeto:

  • **Segregação de fundos:**A estratégia utiliza apenas os 100 USDT especificados e não afeta outros fundos na conta.
  • **Juros compostos automáticos:**Cada lucro é automaticamente adicionado ao capital inicial, de forma que um valor maior será utilizado na próxima posição.
  • **Os riscos são controláveis:**O pior cenário possível é a perda de 100 USDT, o que está dentro das expectativas.
  • **Rastreamento claro:**Ele consegue determinar com precisão quanto a estratégia reinvestiu de 100 USDT.

3.3 Decisão de Rollover: Continuar ou Parar Após Realizar o Lucro?

Este é o elemento central da estratégia de rolagem de posições:Após a execução da ordem de take-profit, precisamos tomar uma decisão crucial: continuar rolando ou parar?

Cenário de tomada de decisão:

假设我们做多BTC: - 入场价:45000 USDT,用100 USDT开仓 - 止盈价:49500 USDT(涨10%) - 止盈成交,盈利30 USDT - 现在资金池:130 USDT 问题来了: 选项A:收手,带着130 USDT退出,回到空仓 选项B:继续,用130 USDT再次开多(滚仓)

Como escolher?

Essa decisão não pode ser baseada em "sentimentos"; devem existir critérios claros. Nossa lógica de julgamento é:Essa tendência vai continuar?

Método de julgamento:
No momento em que a ordem de take-profit é executada, os indicadores técnicos mais recentes (média móvel exponencial) são recalculados:

javascript
// 止盈单成交后,获取最新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 Processo de Execução de Rollover

Se a decisão for "continuar rolando a posição":

javascript
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(); } }

Se a decisão for "parar":

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

Pontos-chave deste processo:

  • Faça um julgamento imediatamente após cada ação que vise a obtenção de lucro, sem demora.
  • Os critérios de avaliação são objetivos (relação entre médias móveis), sem especulação subjetiva.
  • Continue aumentando sua posição; pare e preserve seus ganhos.

3.5 O Poder e o Custo dos Juros Compostos

Vamos vivenciar o poder dos juros compostos por meio de um estudo de caso completo:

Histórias de sucesso:

初始资金: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 falha:

第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

Essa é a faca de dois gumes das negociações de rollover:

  • **Após o sucesso:**O crescimento exponencial é empolgante.
  • **Quando falha:**Recuo rápido, ou mesmo perdas

IV. Pergunta 3: Quando parar? — O stop-loss é a última linha de defesa.

Mecanismo de suspensão

4.1 Dois métodos de saída

Saída proativa: tendência de enfraquecimento
Essa situação já foi abordada na "Questão Dois" — após realizar os lucros, se a tendência indicar que não há mais ganhos, opte ativamente por parar. Essa é a estratégia de saída ideal, deixando o mercado com lucro.

Saída passiva: acionamento do stop loss
É nisto que nos concentraremos agora: quando o mercado se move contra nós e o preço atinge a linha de stop-loss, somos obrigados a fechar as nossas posições.

4.2 A necessidade de stop-loss

Muitas pessoas não gostam de ordens de stop-loss porque:

  • Stop-loss significa admitir um erro.
  • O stop-loss resultará em perdas reais.
  • Às vezes, o preço se recupera após a colocação de uma ordem de stop-loss.

No entanto, na estratégia de posição rolante,**O stop-loss é a medida fundamental para a sobrevivência.**Pense nisso:

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

**A essência do stop loss:**Use perdas pequenas e certas para evitar riscos grandes e incertos.

4.3 Implementação do código stop-loss

javascript
// 检查止损 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 Condições para o término do jogo

Lembra do "Jogo do Aventureiro Racional" de que falamos? Esse jogo tem uma condição de término bem definida:

Condição 1: O capital disponível é reduzido a zero.

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

Condição 2: Retirada voluntária

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

Condição 3: Atingir o número máximo de rollovers

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

4.5 O equilíbrio entre risco e retorno

O cerne de toda a estratégia de posicionamento rotativo está emEncontrar um equilíbrio entre risco e retorno.

Lado da receita:

  • Crescimento composto: O capital inicial aumenta após cada realização de lucros.
  • Captura de tendências: Lucrar consistentemente em tendências de alta/baixa.
  • Sem limite superior: Teoricamente, pode rolar indefinidamente.

Lado de risco:

  • Proteção contra stop-loss: Perda máxima de 5% do capital total em uma única transação.
  • Segregação de fundos: Perda máxima de 100 USDT
  • Análise de tendências: Evite ordens de stop-loss frequentes em um mercado volátil.

V. Backtesting Prático: Análise de Caso TRUMP_USDT

TRUMP_USDTAnálise de backtesting do primeiro dia de listagem da Binance Futures (20 de janeiro de 2025 a 21 de janeiro de 2025):

Backtesting da curva de capital

Tabela de Estatísticas de Rollover

Os resultados do backtest mostram que:

Destaques:

  • A estratégia capturou com sucesso as flutuações dramáticas nos primeiros dias da Trump após seu IPO.
  • Por meio de múltiplas renovações de capital, foi alcançado um rápido crescimento do capital.
  • O mecanismo de realização de lucros efetivamente consolida os lucros dentro de uma tendência.

Exposição ao risco:

  • Quando a tendência se inverte, as ordens de stop-loss fazem com que parte dos lucros seja devolvida.
  • Um sinal falso de rompimento surgiu em um mercado volátil.
  • O risco de concentração é maior com uma única moeda.

Dados principais:

  • Número total de rollovers: X vezes
  • Acumulação máxima de rodadas: X vezes
  • Redução máxima: X%
  • Taxa de retorno final: X%

VI. A natureza e as limitações da estratégia

6.1 O que essa estratégia está simulando?

Através da análise acima, podemos ver claramente que essa estratégia é essencialmente uma simulação:

O comportamento comercial de um aventureiro racional:

  • Existem regras de entrada claras (não se trata de negociação impulsiva).
  • Defina uma meta de lucro (evite a ganância).
  • Tenha disciplina de stop-loss (não mantenha posições perdedoras).
  • Possui a capacidade de tomar decisões de posicionamento rotativas (e utilizar os lucros).
  • Existem restrições de financiamento (para controlar o risco).

Sua lógica fundamental é:

  1. Reserve uma quantia fixa de capital (100 USDT) para experimentar.
  2. Ganhe dinheiro seguindo tendências.
  3. Após obter lucro, utilize-o para continuar negociando (efeito composto dos lucros).
  4. Se a tendência enfraquecer, pare imediatamente.
  5. Se o julgamento estiver errado, minimize suas perdas rapidamente.
  6. Até que os fundos se esgotem ou sejam transferidos para um montante satisfatório.

6.2 Limitações da Estratégia

Limitação 1: Dependência de mercados de tendência
Essa estratégia apresenta baixo desempenho em mercados voláteis porque:

  • Falsos erupções frequentes
  • O preço recuou depois que realizei o lucro, então não consegui rolar a posição.
  • Ordens repetidas de stop-loss esgotam o capital disponível.

Limitação 2: Sensibilidade dos parâmetros
Parâmetros como meta de lucro de 10% e stop loss de 5% não são ideais:

  • Moedas diferentes apresentam volatilidade diferente.
  • Diferentes condições de mercado exigem parâmetros diferentes.
  • Parâmetros fixos são difíceis de adaptar a todas as situações.

Limitação 3: Ponto de detonação imprevisível
Como mencionado anteriormente, usar indicadores técnicos para entrar no mercado é essencialmente uma aposta:

  • Você pode perder as grandes movimentações do mercado.
  • Entrar durante uma falsa fuga
  • Incapazes de planejar com antecedência como os especialistas.

6.3 Áreas para melhoria

Opção 1: Filtrar moedas com base no fluxo de trabalho

  • Não escolha qualquer criptomoeda e saia por aí.
  • Em vez disso, o fluxo de trabalho é usado para filtrar primeiramente as criptomoedas populares e de alto potencial.
  • Por exemplo: um aumento repentino nas discussões em redes sociais, um volume anormal de transações e dados ativos na blockchain.
  • Utilizar uma estratégia de rotação de posições nessas criptomoedas resultará em uma taxa de sucesso maior.

Direção 2: Ajustar parâmetros dinamicamente

  • Ajuste os índices de realização de lucros e de stop-loss com base na volatilidade histórica da moeda.
  • Para moedas altamente voláteis, amplie adequadamente o intervalo de stop-loss.
  • Para criptomoedas com baixa volatilidade, você pode reduzir sua meta de lucro.

Diretriz 3: Múltiplos fundos operando em paralelo

  • Não se trata de colocar 100 USDT em uma única moeda.
  • Em vez disso, é dividido em cinco quantias de 20 USDT, que são transferidas simultaneamente para cinco criptomoedas diferentes.
  • Diversifique o risco e aumente a probabilidade de "ganhar na loteria".

Conclusão

Por meio da dedução de três questões fundamentais, demonstramos plenamente como traduzir a ideia de rolagem de posições em lógica de código. A essência desse processo é:Expresse a mentalidade de negociação de um investidor racional que assume riscos, utilizando regras e estruturas de dados precisas.

Nota importante:

Esta é apenas uma simulação da estratégia de rolagem de posições. Na realidade, a rolagem de posições é uma estratégia de negociação que exige muita experiência de mercado. Esta estratégia é apenas uma ferramenta. Posteriormente, ela poderá ser combinada com fluxos de trabalho para identificar criptomoedas populares ou com potencial de explosão. O uso desta ferramenta nos trará mais surpresas.

Lembre-se:

  • A perda máxima é de 100 USDT, e o risco é administrável.
  • Se você tiver a sorte de identificar uma grande tendência, seu investimento poderá se multiplicar várias vezes ou até dezenas de vezes.
  • Mas, na maioria das vezes, isso pode envolver pequenos ganhos e perdas, e testes repetidos.
  • Este é um jogo que exige paciência e disciplina.

**Não existe estratégia que garanta lucro.**A troca de posições é apenas uma ferramenta. O que realmente determina o sucesso ou o fracasso é a sua capacidade de:

  • Identificar criptomoedas promissoras (usando filtragem de fluxo de trabalho).
  • Respeite as ordens de stop-loss (não se apegue teimosamente à posição).
  • Tenha a ousadia de rolar suas posições quando uma tendência importante surgir (não saia muito cedo).
  • Mantenha a racionalidade (não deixe que suas emoções o controlem).

Que todos vocês encontrem sua própria "grande sorte" em sua jornada de negociação quantitativa!

Endereço completo da política:**Código-fonte da estratégia -> ** https://www.fmz.com/strategy/521864

Código de estratégia completo:

javascript
/*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 表示未成交,继续等待 if (checkCount % 10 == 0) { Log("⏳ 订单未成交,已检测", checkCount, "次..."); } } // 超时,取消订单 Log("⚠️ 平仓订单超时(等待30秒未成交)"); Log("尝试取消订单:", orderId); var cancelResult = exchange.CancelOrder(orderId); if (cancelResult) { Log("✅ 订单已取消"); } else { Log("⚠️ 取消订单失败,订单可能已成交或已取消"); } Sleep(1000); // 再次检查订单状态(可能取消期间成交了) var finalOrder = exchange.GetOrder(orderId); if (finalOrder && finalOrder.Status == 1) { Log("✅ 订单在取消期间成交,成交价:", finalOrder.AvgPrice.toFixed(pricePrecision)); var profit = calculateProfit(pos, finalOrder.AvgPrice); Log("盈亏:", profit.toFixed(2), "U"); return profit; } return 0; } // 计算盈亏 function calculateProfit(position, closePrice) { var profit = 0; if (position.Type == PD_LONG) { // 多头盈亏 = (平仓价 - 开仓价) * 数量 * 合约面值 profit = (closePrice - position.Price) * position.Amount * ctVal; } else { // 空头盈亏 = (开仓价 - 平仓价) * 数量 * 合约面值 profit = (position.Price - closePrice) * position.Amount * ctVal; } return profit; } // ========== 显示状态(三个两行表格) ========== function showStatus(account, position, price, ema5, ema10, isBullTrend, barTime) { // ========== 表格1:基本信息 ========== var table1 = { type: "table", title: "策略基本信息", cols: ["更新时间", "交易币种", "账户总资金", "策略初始资金", "策略当前资金", "策略累计盈利", "策略收益率"], rows: [] }; table1.rows.push([ _D(barTime), Symbol, account.Balance.toFixed(2) + " U", InitialCapital + " U", strategyCapital.toFixed(2) + " U", totalProfitRealized.toFixed(2) + " U", ((strategyCapital / InitialCapital - 1) * 100).toFixed(2) + "%" ]); // ========== 表格2:持仓信息 ========== var table2 = { type: "table", title: "持仓信息", cols: [], rows: [] }; if (position.length > 0) { var pos = position[0]; var totalPL = 0; if (pos.Type == PD_LONG) { totalPL = (price - entryPrice) / entryPrice; } else { totalPL = (entryPrice - price) / entryPrice; } var stopLossPrice = 0; var takeProfitPrice = 0; if (pos.Type == PD_LONG) { stopLossPrice = entryPrice * (1 - StopLossPercent); takeProfitPrice = entryPrice * 1.1; } else { stopLossPrice = entryPrice * (1 + StopLossPercent); takeProfitPrice = entryPrice * 0.9; } table2.cols = [ "持仓状态", "持仓方向", "持仓数量", "入场价格", "持仓均价", "止盈价格", "止损价格", "浮动盈亏", "盈亏比例", "止盈单ID", "本轮滚仓次数" ]; table2.rows.push([ "✅ 持仓中", pos.Type == PD_LONG ? "🟢 多头" : "🔴 空头", pos.Amount.toFixed(amountPrecision), entryPrice.toFixed(pricePrecision), pos.Price.toFixed(pricePrecision), takeProfitPrice.toFixed(pricePrecision), stopLossPrice.toFixed(pricePrecision), pos.Profit.toFixed(2) + " U", (totalPL * 100).toFixed(2) + "%", takeProfitOrderId ? takeProfitOrderId : "未挂单", currentRoundRolls + " 次" ]); } else { table2.cols = ["持仓状态", "等待信号", "本轮滚仓次数"]; table2.rows.push([ "⏳ 空仓", isBullTrend ? "📈 等待金叉" : "📉 等待死叉", currentRoundRolls + " 次" ]); } // ========== 表格3:滚仓统计(近10次详细记录) ========== var table3 = { type: "table", title: "滚仓统计(近10次)", cols: ["序号", "方向", "入场价格", "开始时间", "结束时间", "滚仓次数", "盈利金额", "亏损金额", "总体盈利", "持续时间"], rows: [] }; if (rollHistory.length == 0) { table3.rows.push(["暂无", "暂无", "暂无", "暂无", "暂无", "暂无", "暂无", "暂无", "暂无", "暂无"]); } else { // 倒序显示(最新的在前) for (var i = rollHistory.length - 1; i >= 0; i--) { var record = rollHistory[i]; var index = rollHistory.length - i; var directionText = record.direction == "LONG" ? "🟢 多头" : "🔴 空头"; // 总体盈利的显示(带颜色标识) var netProfitText = record.netProfit.toFixed(2) + " U"; if (record.netProfit > 0) { netProfitText = "+" + netProfitText; } // 格式化时间显示(只显示月-日 时:分) var startTimeStr = _D(record.startTime).substring(5, 16); // "MM-DD HH:mm" var endTimeStr = _D(record.endTime).substring(5, 16); table3.rows.push([ "#" + index, directionText, record.entryPrice ? record.entryPrice.toFixed(pricePrecision) : "未知", startTimeStr, endTimeStr, record.roundRolls + " 次", record.totalProfit.toFixed(2) + " U", record.loss.toFixed(2) + " U", netProfitText, formatDuration(record.duration) ]); } } // ========== 组合所有表格 ========== LogStatus( "`" + JSON.stringify(table1) + "`\n\n" + "`" + JSON.stringify(table2) + "`\n\n" + "`" + JSON.stringify(table3) + "`" ); }
Comment
All comments (0)
No data
No data
  • 1
Forums
PINE Language
Get the app
iPhone Download
© 2015 - ∞ INVENTOR PTE LTD (SG)