avatar of ianzeng123 ianzeng123
집중하다 사신
2
집중하다
410
수행원

모험가들의 게임: 롤오버 전략의 코드 구현 및 적용

만든 날짜: 2025-12-19 17:06:01, 업데이트 날짜: 2025-12-29 09:04:46
comments   0
hits   353

[TOC]

모험가들의 게임: 롤오버 전략의 코드 구현 및 적용

소개

양적 거래 분야에서 롤링 포지션 전략은 매력적이면서도 어려운 주제입니다. 이 전략의 핵심 아이디어는 추세가 있는 시장에서 실현된 수익을 재투자하여 복리 성장을 달성하는 것입니다. 이 글에서는 기술적인 세부 사항보다는 사고방식의 변화에 ​​초점을 맞춰 이 거래 아이디어를 실행 가능한 코드 로직으로 단계별로 구현하는 방법을 자세히 살펴보겠습니다. 롤링 포지션 전략은 수익을 증폭시키지만 위험 또한 증폭시킨다는 점을 유념해야 합니다. 이 글은 학습 및 토론 목적으로만 작성되었습니다.


I. 롤링 포지션 전략의 수익 논리에 대한 심층 분석

1.1 롤오버의 수학적 본질

롤오버 다이어그램

롤링 포지션 전략의 수익 논리는 본질적으로 다음과 같습니다.복합 성장 모델간단한 예를 통해 이를 이해해 봅시다.

전통적인 단일 거래 방식 (3회 연속 10%씩 인상):

  • 초기 자본금: 100 USDT, 레버리지: 3배
  • 시장 증가율: (1+10%) × (1+10%) × (1+10%) - 1 = 33.1%
  • 수익: 100 × 3 × 33.1% = 99.3 USDT
  • 최종 가격: 199.3 USDT

롤오버 거래(연속 3회 거래, 각 거래마다 10%씩 증가):

  • 처음100 USDT → 30 USDT 수익 → 자금 130 USDT
    • 계산: 100 × 3배 레버리지 × 10% 증가 = 30
  • 두 번째130 USDT → 39 USDT 수익 → 잔액 169 USDT
    • 계산: 130 × 3배 레버리지 × 10% 증가 = 39
  • 3번째169 USDT → 50.7 USDT 수익 → 잔액 219.7 USDT로 증가
    • 계산: 169 × 3배 레버리지 × 10% 증가 = 50.7

비교 결과:

시장이 3회 연속 10% 상승하는 동일한 시나리오에서:

  • 단일 거래99.3 USDT의 수익
  • 롤오버 거래119.7 USDT의 수익
  • 복리의 장점20.4 USDT (약 20.5% 증가)

마찬가지로, 10%씩 3회 연속 상승했을 경우 단일 거래 수익은 99.3 USDT였고, 포지션을 롤오버했을 때의 수익은 119.7 USDT였습니다.이러한 차이가 바로 복리 효과의 힘입니다.

수학 공식을 사용하여 표현하면 다음과 같습니다.

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

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

이것이 바로 롤오버의 본질을 보여줍니다.선형 성장을 지수적 성장으로 전환하기하지만 이는 또한 위험을 드러냈습니다.단 한 번의 손절매 주문으로 지금까지 쌓아온 모든 복리 수익이 날아갈 수 있습니다.

1.2 롤오버 전략의 세 가지 핵심 문제

코드를 작성하기 전에 전략적 관점에서 세 가지 기본적인 질문에 답해야 합니다.

질문 1: 언제 시작되나요? (첫 번째 항목)
추세의 시작 신호를 파악하는 것이 필요합니다.

질문 2: 언제 계속 진행해야 합니까? (추가 롤링 위치)
이것이 바로 포지션을 롤오버하는 핵심입니다. 즉, 수익 실현 후에도 추세가 지속될지 여부를 판단하는 방법입니다.

질문 3: 언제 중단해야 할까요? (철수 후 관찰)

  • 선제적 퇴출: 약화 추세
  • 수동적 청산: 손절매 실행

이 세 가지 질문은 전체 전략의 틀을 결정하며, 이제 우리는 이 질문들을 하나씩 코드 로직으로 변환해 나갈 것입니다.


II. 질문 1: 언제 시작해야 할까요? — 진입 시점을 결정하는 중요한 기준점 찾기.

출입 신호

2.1 롤오버 전략의 이상과 현실

먼저 롤링 포지션 전략의 이상적인 적용 시나리오를 이해해 보겠습니다.

이상적인 시나리오:
SHIB 시장이 0.000001달러에서 상승하기 시작할 때 진입하거나, 특정 알트코인이 급등하기 직전에 포지션을 구축할 수 있다고 상상해 보세요. 지속적인 롤오버를 통해 100 USDT가 잠재적으로 10,000 USDT 또는 그 이상이 될 수 있습니다. 이것이 바로 롤오버 전략의 궁극적인 목표입니다.암호화폐 시장이 폭발적으로 성장하기 전에 진입하여 10배, 심지어 100배의 수익을 올리세요.

냉혹한 현실:
문제는 어떤 암호화폐가 급등할지, 그리고 언제 급등할지 어떻게 알 수 있느냐는 것입니다.

  • 프로젝트 책임자 또는 내부 관계자라면 긍정적인 소식에 대해 미리 알고 있을 수도 있습니다.
  • 일반적인 투자자라면 시장 신호에 근거해서만 판단을 내릴 수 있습니다.

우리 대부분에게 있어 이러한 전환점을 정확하게 포착하는 것은…솔직히 말해서, 전부 운에 달린 거죠.우리는 미래를 예측할 수 없습니다. 다만 과거 데이터와 기술적 지표를 활용하여 “대박”을 터뜨릴 확률을 높이려고 노력할 수 있을 뿐입니다.

2.2 이상에서 현실로: 기술적 지표 기반 시뮬레이션 진입

어떤 암호화폐의 가격이 급등할지 예측할 수 없으므로 우리가 할 수 있는 일은 다음과 같습니다.실행 가능한 진입 규칙을 수립하고 기술적 지표를 활용하여 “추세 시작” 신호를 시뮬레이션하십시오.

마치 드넓은 바다에서 낚시하는 것과 같습니다. 큰 물고기가 어디에 있는지 몰라도, 우리는 다음과 같은 것들을 할 수 있습니다.

  • 수면의 잔물결(가격 변동)을 관찰하세요.
  • 물의 흐름 방향(추세 방향)을 분석하십시오.
  • 적절한 도구(기술 지표)를 선택하십시오.

여러 신호가 수렴될 때, 우리는 추세가 시작될 가능성이 있다고 판단하여 시장에 진입합니다. 예측이 맞으면 추세를 따라 포지션을 재조정하여 수익을 내고, 예측이 틀리면 손실을 최소화하고 즉시 시장에서 빠져나옵니다.

2.3 진입 신호의 기술적 구현

기술 도구 선택:
우리는 추세 파악 도구로 EMA 이중 이동 평균 시스템(EMA5 및 EMA10)을 사용합니다. 이 시스템을 선택한 이유는 간단합니다.

  • 간단하고 직관적이며 검증하기 쉽습니다.
  • 가격 변동에 신속하게 대응할 수 있음
  • 매개변수는 감도와 안정성의 균형을 맞춥니다.

핵심 논리:
이동평균선의 “골든 크로스”(EMA5가 EMA10 위로 교차하는 현상)와 “데스 크로스”(EMA5가 EMA10 아래로 교차하는 현상)를 감지함으로써 추세 반전 지점을 포착할 수 있습니다.

  • 골든 크로스 → 매수 신호
  • 데스 크로스 → 공매도 신호

코드는 다음과 같습니다.

// 计算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);
}

이 섹션에서는 골든 크로스와 데스 크로스에 대한 자세한 내용은 다루지 않겠습니다. 이는 트레이딩의 기본 개념이기 때문입니다. 핵심은 다음과 같습니다.가격 상승을 시작하려면 명확하고 정량화 가능한 진입 신호가 필요합니다.


III. 질문 2: 언제 계속해야 할까요? — 복리 이자의 핵심 메커니즘.

전복 방지 장치

3.1 롤오버의 본질 이해하기: 합리적인 모험가를 위한 게임

롤오버 전략은 본질적으로 다음과 같습니다.합리적인 모험 게임실제 시나리오를 통해 이를 이해해 봅시다.

게임 규칙:

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

이 게임의 뛰어난 점은 다음과 같습니다.

  • 위험은 관리 가능한 수준입니다. 최대 손실액은 100 USDT이며, 이는 계좌의 다른 자금에 영향을 미치지 않습니다.
  • 무제한 수익: 추세가 맞아떨어지면 복리 이자로 인해 원금이 빠르게 두 배로 늘어날 수 있습니다.
  • 진입 및 청산에 대한 명확한 규칙: 이익 실현, 손절매 및 포지션 재진출에 대한 명확한 규칙.

3.2 자본 풀 설계: 복리 이자 실현의 핵심

이것이 바로 롤링 포지션 전략의 핵심 설계 개념입니다.

전통적인 관행의 문제점:
거래소 계정에 1000 USDT가 있다고 가정해 보겠습니다.

  • 첫 번째 포지션은 100 USDT로 개설되었습니다.
  • 30 USDT의 수익을 낸 후, 계좌 잔액은 1030 USDT가 되었습니다.
  • 두 번째 시작 포지션에 얼마를 사용해야 할까요? 100일까요, 아니면 130일까요?
  • 수익이 롤링 포지션 전략에서 발생한 것인지 아니면 다른 운영에서 발생한 것인지 어떻게 구분할 수 있을까요?

자금 공동 운용 솔루션:

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

이 디자인의 장점:

  • 펀드 분리:이 전략은 지정된 100 USDT만 사용하며 계좌의 다른 자금에는 영향을 미치지 않습니다.
  • 자동 복리 이자:수익은 자동으로 자본 풀에 추가되므로 다음 투자에는 더 큰 금액이 사용됩니다.
  • 위험은 통제 가능합니다.최악의 경우 100 USDT를 잃는 것인데, 이는 예상 범위 내입니다.
  • 명확한 추적:이 기능을 통해 100 USDT에서 전략이 얼마나 이월되었는지 정확하게 파악할 수 있습니다.

3.3 롤오버 결정: 수익 실현 후 계속 진행할 것인가, 아니면 중단할 것인가?

이것이 바로 롤링 포지션 전략의 핵심 요소입니다.이익 실현 주문이 체결된 후에는 중요한 결정을 내려야 합니다. 계속 롤링할지, 아니면 멈출지 말입니다.

의사결정 시나리오:

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

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

어떻게 선택해야 할까요?

이 결정은 “감정”에 근거해서는 안 되며, 명확한 기준이 있어야 합니다. 우리의 판단 논리는 다음과 같습니다.이러한 추세가 계속되고 있나요?

판단 방법:
이익실현 주문이 체결되는 순간, 최신 기술 지표(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 롤오버 실행 프로세스

결정 사항이 “해당 포지션을 계속 롤오버”인 경우:

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

결정이 “정지”인 경우:

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

이 과정의 핵심 사항은 다음과 같습니다.

  • 각 이익 실현 행위 직후 지체 없이 즉시 판단을 내리십시오.
  • 판단 기준은 주관적인 추측이 개입되지 않은 객관적인 기준(이동평균 간의 관계)에 기반합니다.
  • 보유량을 계속 늘리되, 수익을 보존하기 위해 손절매하십시오.

3.5 복리의 힘과 비용

복리 효과의 위력을 실례 사례를 통해 경험해 봅시다.

성공 사례:

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

실패 사례:

第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

이것이 바로 롤오버 트레이딩의 양날의 검입니다.

  • 성공 시:기하급수적 성장은 흥미롭습니다.
  • 실패할 경우:급격한 하락 또는 손실

IV. 질문 3: 언제 멈춰야 할까요? — 손절매는 최후의 방어선입니다.

손해 방지 장치

4.1 두 가지 종료 방법

선제적 퇴출: 약화 추세
이 상황은 이미 “질문 2”에서 다루었습니다. 수익을 실현한 후 추세가 더 이상의 상승을 뒷받침하지 않는다고 판단되면 적극적으로 손절매를 선택하십시오. 이것이 수익을 내고 시장에서 빠져나오는 이상적인 출구 전략입니다.

수동적 청산: 손절매 실행
지금부터 우리가 집중할 부분은 바로 이것입니다. 시장이 우리에게 불리하게 움직여 가격이 손절매선에 도달하면, 우리는 포지션을 청산할 수밖에 없습니다.

4.2 손절매의 필요성

많은 사람들이 손절매 주문을 싫어하는 이유는 다음과 같습니다.

  • 손절매는 실수를 인정하는 것을 의미합니다.
  • 손절매는 실제 손실을 초래할 수 있습니다.
  • 손절매 주문을 설정한 후 가격이 반등하는 경우가 있습니다.

하지만, 롤링 포지션 전략에서는,손절매는 생존의 핵심입니다.한번 생각해 보세요:

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

손절매의 핵심:작고 확실한 손실을 이용하여 크고 불확실한 위험을 피하십시오.

4.3 손절매의 코드 구현

// 检查止损
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 게임 종료 조건

우리가 이야기했던 “합리적인 모험가의 게임”을 기억하시나요? 이 게임에는 명확한 종료 조건이 있습니다.

조건 1: 자본금이 0으로 감소합니다.

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

조건 2: 자발적 철회

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

조건 3: 최대 롤오버 횟수에 도달

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

4.5 위험과 수익의 균형

전체 롤링 포지션 전략 설계의 핵심은 다음과 같습니다.위험과 수익 사이의 균형 찾기

수익 측면:

  • 복리 성장: 이익 실현 조치가 있을 때마다 자본 풀이 증가합니다.
  • 추세 포착: 상승/하락 추세에서 꾸준히 수익을 내는 방법
  • 상한선 없음: 이론적으로는 무한히 굴러갈 수 있습니다.

위험 요소:

  • 손절매 보호: 단일 거래에서 자본금의 최대 5%까지만 손실이 발생하도록 제한합니다.
  • 자금 분리: 최대 손실액 100 USDT
  • 추세 분석: 변동성이 큰 시장에서는 손절매 주문을 자주 사용하지 마십시오.

V. 실제 백테스팅: TRUMP_USDT 사례 분석

TRUMP_USDT바이낸스 선물거래소 상장 첫날(2025년 1월 20일~2025년 1월 21일)에 대한 백테스팅 분석:

백테스팅 자산 곡선

롤오버 통계표

백테스트 결과는 다음과 같습니다.

하이라이트:

  • 이 전략은 트럼프의 기업공개(IPO) 직후 초기 몇 주 동안 나타난 급격한 주가 변동을 성공적으로 포착했습니다.
  • 여러 차례의 롤오버를 통해 빠른 자본 성장을 달성했습니다.
  • 이익 실현 메커니즘은 추세 내에서 이익을 효과적으로 확보합니다.

위험 노출:

  • 추세가 반전되면 손절매 주문으로 인해 일부 수익이 반환됩니다.
  • 변동성이 큰 시장에서 잘못된 돌파 신호가 나타났습니다.
  • 단일 통화를 사용할 경우 집중 위험이 더 높습니다.

주요 데이터:

  • 총 롤오버 횟수: X회
  • 최대 단일 라운드 롤오버 횟수: X회
  • 최대 손실률: X%
  • 최종 수익률: X%

VI. 전략의 본질과 한계

6.1 이 전략은 무엇을 시뮬레이션하는 것입니까?

위 분석을 통해 우리는 이 전략이 본질적으로 시뮬레이션이라는 것을 분명히 알 수 있습니다.

합리적인 모험가의 거래 행태:

  • 명확한 진입 규칙이 있습니다(충동적인 거래는 지양해야 합니다).
  • 수익 목표를 설정하세요 (탐욕을 피하세요).
  • 손실 제한 규칙을 준수하세요 (손실이 나는 포지션을 계속 보유하지 마세요).
  • 포지션을 지속적으로 조정하고 수익을 활용할 수 있는 능력을 갖추고 있습니다.
  • (위험 관리를 위해) 자금 조달에 제한이 있습니다.

그 핵심 논리는 다음과 같습니다.

  1. 시험 삼아 일정 금액(100 USDT)을 따로 마련해 두세요.
  2. 트렌드를 따라가면 돈을 벌 수 있습니다.
  3. 수익을 낸 후에는 그 수익을 재투자하여 거래를 계속하십시오(수익 복리).
  4. 추세가 약해지면 즉시 중단하십시오.
  5. 판단이 잘못되었다면 손실을 최소화해야 합니다.
  6. 자금이 소진되거나 만족스러운 금액으로 이월될 때까지.

6.2 전략의 한계

제한사항 1: 추세 시장에 대한 의존
이 전략은 변동성이 큰 시장에서 성과가 저조한 이유는 다음과 같습니다.

  • 잦은 거짓 돌파
  • 제가 수익을 실현한 후 가격이 되돌림되어서 포지션을 롤오버할 수 없었습니다.
  • 반복적인 손절매 주문은 자본금을 고갈시킵니다.

제한사항 2: 매개변수 민감도
10% 수익 목표와 5% 손절매와 같은 매개변수는 최적의 설정이 아닙니다.

  • 각 통화는 서로 다른 변동성을 가지고 있습니다.
  • 시장 상황에 따라 요구되는 매개변수가 달라집니다.
  • 고정된 매개변수는 모든 상황에 적용하기 어렵습니다.

제한사항 3: 예측 불가능한 폭발 지점
앞서 언급했듯이 기술적 지표를 이용하여 시장에 진입하는 것은 본질적으로 도박과 같습니다.

  • 시장의 큰 변동을 놓칠 수도 있습니다.
  • 거짓 돌파 중에 진입하세요
  • 내부자처럼 미리 계획을 세울 수 없다

6.3 개선이 필요한 영역

옵션 1: 워크플로에 따라 통화 필터링

  • 아무 암호화폐나 골라서 투자하고 떠나지 마세요.
  • 대신, 이 워크플로는 먼저 인기 있고 잠재력이 높은 암호화폐를 걸러내는 데 사용됩니다.
  • 예를 들어 소셜 미디어 토론 급증, 비정상적인 거래량, 활발한 온체인 데이터 등이 있습니다.
  • 이러한 암호화폐에 롤링 포지션 전략을 사용하면 성공률이 높아집니다.

방향 2: 매개변수를 동적으로 조정

  • 통화의 과거 변동성을 기준으로 이익 실현 및 손절매 비율을 조정하십시오.
  • 변동성이 매우 높은 통화의 경우, 손절매 범위를 적절히 넓히십시오.
  • 변동성이 낮은 암호화폐의 경우 수익 목표를 낮출 수 있습니다.

방향 3: 여러 펀드 풀이 병렬적으로 운영됨

  • 100 USDT를 한 가지 통화로 바꾸는 문제가 아닙니다.
  • 대신, 20 USDT씩 5개의 금액으로 나뉘어 5개의 잠재적 암호화폐에 동시에 롤오버됩니다.
  • 위험을 분산시키고 대박을 터뜨릴 확률을 높이세요.

결론

세 가지 핵심 질문을 도출함으로써, 포지션 롤오버라는 거래 아이디어를 코드 로직으로 구현하는 방법을 완벽하게 보여주었습니다. 이 과정의 핵심은 다음과 같습니다.정확한 규칙과 데이터 구조를 사용하여 합리적인 위험 감수자의 거래 사고방식을 표현하십시오.

중요 사항:

이것은 롤링 포지션 전략의 시뮬레이션일 뿐입니다. 실제 롤링 포지션은 풍부한 시장 경험을 요구하는 거래 전략입니다. 이 전략은 단지 도구일 뿐이며, 나중에는 인기 있거나 급등할 가능성이 높은 암호화폐를 식별하는 워크플로우와 결합하여 활용할 수 있습니다. 이 도구를 제대로 활용하면 더욱 놀라운 결과를 얻을 수 있을 것입니다.

기억하세요:

  • 최대 손실액은 100 USDT이며, 위험은 관리 가능한 수준입니다.
  • 운 좋게 주요 트렌드를 포착한다면 투자금이 몇 배, 심지어 수십 배로 불어날 수도 있습니다.
  • 하지만 대부분의 경우, 이는 작은 이득과 손실을 수반하고 반복적인 테스트를 거치게 될 수 있습니다.
  • 이 게임은 인내심과 규율을 요구합니다.

수익을 보장하는 전략은 없습니다.포지션을 이전하는 것은 단지 도구일 뿐입니다. 진정한 성공과 실패를 결정하는 것은 바로 다음과 같은 능력입니다.

  • 워크플로우 필터링을 사용하여 유망한 암호화폐를 식별합니다.
  • 손절매 주문을 준수하세요 (굳이 고집하지 마세요).
  • 주요 추세가 나타나면 과감하게 포지션을 재조정하세요(너무 일찍 빠져나오지 마세요).
  • 이성적인 판단을 유지하세요 (감정에 휘둘리지 마세요).

양적 트레이딩 여정에서 여러분 모두 각자의 “큰 행운”을 찾으시길 바랍니다!

전체 정책 주소:**전략 소스 코드 -> ** https://www.fmz.com/strategy/521864

완전한 전략 코드:

”`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() - startTim