dubaitrade.fr
Crypto · 10/29/2025

Exécuteur (boucle principale)

Espace publicitaire (in-article 1)
// src/executor.ts
import 'dotenv/config'
import pino from 'pino'
import crypto from 'node:crypto'
import { CcxtAdapter } from './broker/ccxt-adapter'
import { generateSignal, Candle } from './strategy'
import { positionSize, withinExposure } from './risk'
import { appendOrder } from './journal'

const log = pino({ level: 'info' })

function cid(prefix='ORD'): string {
  return `${prefix}-${Date.now()}-${crypto.randomBytes(3).toString('hex')}`
}

async function main() {
  const exId = process.env.EXCHANGE || 'binanceusdm'
  const symbol = process.env.SYMBOL || 'BTC/USDT'
  const timeframe = process.env.TIMEFRAME || '1h'
  const fast = Number(process.env.SMA_FAST || 20)
  const slow = Number(process.env.SMA_SLOW || 50)
  const riskPct = Number(process.env.RISK_MAX_PCT || 0.01)
  const maxExposure = Number(process.env.MAX_EXPOSURE_PCT || 0.2)

  const ex = new CcxtAdapter({
    id: exId,
    apiKey: process.env.EXCHANGE_API_KEY || '',
    secret: process.env.EXCHANGE_API_SECRET || '',
    testnet: String(process.env.EXCHANGE_TESTNET).toLowerCase() === 'true',
  })

  const raw = await ex.fetchOHLCV(symbol, timeframe, 400)
  const candles: Candle[] = raw.map(([t,o,h,l,c,v]) => ({ time:t, open:o, high:h, low:l, close:c, volume:v }))
  const signal = generateSignal(candles, fast, slow)
  log.info({ symbol, signal }, 'Signal')

  if (signal === 'HOLD') return

  // Exposition et taille
  const balance = await ex.balanceUSDT()
  const last = candles[candles.length-1].close
  const size = positionSize(balance, last, riskPct)
  const exposure = (size * last) / Math.max(balance, 1)
  if (!withinExposure(exposure, maxExposure)) {
    return log.warn({ exposure, maxExposure }, 'Exposition trop élevée, pas d’ordre')
  }

  const side = signal === 'BUY' ? 'buy' : 'sell'
  const orderId = cid()
  const order = await ex.createOrder({ symbol, side, type:'market', amount: size, clientOrderId: orderId })
  appendOrder([new Date().toISOString(), symbol, side, size, last, order.id, order.status])
  log.info({ order }, 'Ordre envoyé')
}

main().catch(err => {
  // journal d’erreur
  console.error(err)
  process.exit(1)
})
Espace publicitaire (in-article 2)

Articles reliés