{
  "name": "AlphaPulse Pro - TradingView Dual-Engine Webhook Order Router",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "alphapulse-dual-engine-signal",
        "responseMode": "onReceived",
        "options": {}
      },
      "id": "a1b2c3d4-0001-4000-8000-000000000001",
      "name": "TradingView Webhook Receiver",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [220, 300],
      "webhookId": "alphapulse-dual-engine-signal"
    },
    {
      "parameters": {
        "jsCode": "const body = $input.first().json.body || $input.first().json;\nconst expectedSecret = $env.TRADINGVIEW_WEBHOOK_SECRET || 'AP_PRO_2026_SECRET';\n\nif (body.secret !== expectedSecret) {\n  throw new Error('Unauthorized Webhook Secret Token');\n}\n\nconst entry = Number(body.price || 84085);\nconst stopLoss = Number(body.stopLoss || 82430);\nconst tp1 = Number(body.tp1 || 84570);\nconst tp2 = Number(body.tp2 || 85824);\nconst equityUsd = Number($env.ACCOUNT_EQUITY_USD || 10000);\nconst maxRiskPerTradePct = 0.012; // 1회 최대 계좌 리스크 1.2% 고정\n\nconst stopDistancePct = Math.max(Math.abs(entry - stopLoss) / entry, 0.005);\nconst riskAmountUsd = equityUsd * maxRiskPerTradePct;\nconst recommendedPositionUsd = Math.min(Math.round(riskAmountUsd / stopDistancePct), equityUsd * (Number(body.allocationPct || 50) / 100));\nconst qtyBtc = Number((recommendedPositionUsd / entry).toFixed(4));\nconst rrRatio = Number(((tp2 - entry) / Math.max(entry - stopLoss, 1)).toFixed(2));\n\nconst engineLabel = body.engine === 'ENGINE_1_BREAKOUT'\n  ? '🚀 [Engine 1] 20 EMA & 볼린저 스퀴즈 돌파'\n  : '🧲 [Engine 2] 20 VWAP & RSI 유동성 스윕 역추세';\n\nreturn [{\n  json: {\n    verified: true,\n    timestampKst: new Date().toLocaleString('ko-KR', { timeZone: 'Asia/Seoul' }),\n    symbol: body.symbol || 'BINANCE:BTCUSDT',\n    timeframe: body.timeframe || '240',\n    engine: body.engine || 'ENGINE_2_VWAP_SWEEP',\n    engineLabel,\n    action: body.action || 'BUY_LONG',\n    entryPrice: entry,\n    stopLossPrice: stopLoss,\n    tp1Price: tp1,\n    tp2Price: tp2,\n    stopDistancePct: (stopDistancePct * 100).toFixed(2) + '%',\n    rewardRiskRatio: `1 : ${rrRatio}`,\n    accountEquityUsd: equityUsd,\n    positionSizeUsd: recommendedPositionUsd,\n    orderQtyBtc: qtyBtc,\n    indicators: {\n      rsi14: body.rsi || 36.4,\n      adx14: body.adx || 21.8,\n      atr14: body.atr || 918.9\n    },\n    telegramMessage: `⚡ *AlphaPulse Pro 듀얼 엔진 실시간 시그널*\\n\\n` +\n      `• *발동 엔진:* ${engineLabel}\\n` +\n      `• *대상 종목:* ${body.symbol || 'BINANCE:BTCUSDT'} (${body.timeframe || '4H'})\\n` +\n      `• *진입 단가:* $${entry.toLocaleString()}\\n` +\n      `• *기계적 손절가 (SL):* $${stopLoss.toLocaleString()} (-${(stopDistancePct * 100).toFixed(2)}%)\\n` +\n      `• *1차 익절가 (TP1 60%):* $${tp1.toLocaleString()}\\n` +\n      `• *2차 익절가 (TP2 40%):* $${tp2.toLocaleString()}\\n` +\n      `• *기대 손익비:* 1 : ${rrRatio}\\n` +\n      `• *권장 진입 규모 (1.2% 리스크 기준):* $${recommendedPositionUsd.toLocaleString()} (${qtyBtc} BTC)`\n  }\n}];"
      },
      "id": "a1b2c3d4-0001-4000-8000-000000000002",
      "name": "Risk Guard & Kelly Position Sizer",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [480, 300]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://api.telegram.org/bot{{$env.TELEGRAM_BOT_TOKEN || 'YOUR_BOT_TOKEN'}}/sendMessage",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"chat_id\": \"{{$env.TELEGRAM_CHAT_ID || '@alphapulse_pro_signals'}}\",\n  \"text\": {{ JSON.stringify($json.telegramMessage) }},\n  \"parse_mode\": \"Markdown\"\n}",
        "options": {
          "timeout": 10000
        }
      },
      "id": "a1b2c3d4-0001-4000-8000-000000000003",
      "name": "Telegram VIP Signal Broadcast",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [760, 200],
      "continueOnFail": true
    },
    {
      "parameters": {
        "jsCode": "// 거래소 API (Binance Futures / Upbit) 전송용 표준 주문 페이로드 생성\nconst sig = $input.first().json;\nreturn [{\n  json: {\n    status: 'READY_FOR_EXCHANGE_EXECUTION',\n    exchange: 'BINANCE_USDT_FUTURES',\n    orderPayload: {\n      symbol: sig.symbol.replace('BINANCE:', ''),\n      side: 'BUY',\n      positionSide: 'LONG',\n      type: 'LIMIT',\n      quantity: sig.orderQtyBtc,\n      price: sig.entryPrice,\n      stopLossTrigger: sig.stopLossPrice,\n      takeProfitTargets: [\n        { pct: 60, price: sig.tp1Price },\n        { pct: 40, price: sig.tp2Price }\n      ]\n    }\n  }\n}];"
      },
      "id": "a1b2c3d4-0001-4000-8000-000000000004",
      "name": "Binance & Upbit Order Formatter",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [760, 400]
    }
  ],
  "connections": {
    "TradingView Webhook Receiver": {
      "main": [
        [
          {
            "node": "Risk Guard & Kelly Position Sizer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Risk Guard & Kelly Position Sizer": {
      "main": [
        [
          {
            "node": "Telegram VIP Signal Broadcast",
            "type": "main",
            "index": 0
          },
          {
            "node": "Binance & Upbit Order Formatter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}
