// strategy.js import logger from './logger.js'; import {OpenAI} from "openai"; const openai = new OpenAI({ baseURL: 'https://openrouter.ai/api/v1', apiKey: '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', }); export async function aiSignal(bars) { if (bars.length < 20) return null; // const time = '15분' const time = '1시간' console.log(Date.now()) const completion = await openai.chat.completions.create({ model: 'qwen/qwen3-235b-a22b-2507', messages: [ { role: 'user', content: ` You are a BTC/USDT 1-hour swing-trading engine. - Timeframe: 1h candles only. - Daily trade frequency target: ≥ 3 valid setups. - Risk per trade: 1 % of account or less. - Reward-to-Risk: minimum 2.0, target 2.5. - Never hold more than 1 concurrent position. - Do not add commentary outside the final JSON. [INPUT] Exactly 50 recent 1-hour candles, newest last, format: [{"t":,"o":,"h":,"l":,"c":,"v":}, …] LONG : - 9-EMA > 21-EMA (both rising) - RSI14 between 40 and 65 and increasing vs previous candle - Close ≥ VWAP - Close ≤ Swing High - ATR14×0.5 (small pullback zone) SHORT : exact opposite of LONG. HOLD : if neither LONG nor SHORT conditions are met. Return JSON only, no spaces after colons: {"side":"LONG|SHORT|HOLD","price":,"sl":,"tp":,"reason":""} Entry Price (limit) = current candle close ± 0.05 % toward desired direction. Stop-Loss (SL) = Entry ± ATR14 × 1.0 (beyond nearest Swing Low/High). Take-Profit (TP) = Entry ± ATR14 × 2.5 (minimum 2 R). Round all prices to exchange tick size (0.1 USDT). reason 은 한국어로 대답해줘. ${JSON.stringify(bars)} `, }, ], }); console.log(Date.now()) const msg = completion.choices[0].message.content logger.info(msg); const sig = JSON.parse(msg) return sig; }