Bot & Automation

Treding Forex Ai

/root/hermes-projects/Treding Forex Ai

dist/src/services/market-data/marketDataService.js text
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createMarketDataService = createMarketDataService;
const markets_1 = require("../../constants/markets");
function createMarketDataService(provider, twelveDataApiKey) {
    const demoService = new DemoMarketDataService();
    if (provider === "twelvedata") {
        return new FallbackMarketDataService(new TwelveDataMarketDataService(twelveDataApiKey), demoService);
    }
    return demoService;
}
class FallbackMarketDataService {
    primary;
    fallback;
    constructor(primary, fallback) {
        this.primary = primary;
        this.fallback = fallback;
    }
    async getCandles(symbol, timeframe, limit) {
        try {
            return await this.primary.getCandles(symbol, timeframe, limit);
        }
        catch (error) {
            const fallbackResult = await this.fallback.getCandles(symbol, timeframe, limit);
            const message = error instanceof Error ? error.message : "market data provider failed";
            return {
                ...fallbackResult,
                warning: `Provider realtime gagal, memakai demo data. Detail aman: ${message}`
            };
        }
    }
}
class DemoMarketDataService {
    async getCandles(symbol, timeframe, limit) {
        return {
            candles: buildDemoCandles(symbol, timeframe, limit),
            source: "demo"
        };
    }
}
class TwelveDataMarketDataService {
    apiKey;
    constructor(apiKey) {
        this.apiKey = apiKey;
    }
    async getCandles(symbol, timeframe, limit) {
        if (!this.apiKey) {
            throw new Error("TWELVEDATA_API_KEY kosong");
        }
        const query = new URLSearchParams({
            symbol: toTwelveDataSymbol(symbol),
            interval: toTwelveDataInterval(timeframe),
            outputsize: String(limit),
            apikey: this.apiKey
        });
        const response = await fetch(`https://api.twelvedata.com/time_series?${query.toString()}`);
        const payload = (await response.json());
        if (!response.ok || payload.status === "error" || !Array.isArray(payload.values)) {
            throw new Error(payload.message ?? "Twelve Data response tidak valid");
        }
        const candles = payload.values
            .map((value) => ({
            time: value.datetime,
            open: Number(value.open),
            high: Number(value.high),
            low: Number(value.low),
            close: Number(value.close),
            volume: Number(value.volume ?? 0)
        }))
            .filter((candle) => Number.isFinite(candle.close))
            .reverse();
        return {
            candles,
            source: "twelvedata"
        };
    }
}
function buildDemoCandles(symbol, timeframe, limit) {
    const basePrice = getBasePrice(symbol.code);
    const volatility = symbol.code === "XAUUSD" ? 2.8 : symbol.pipSize * 18;
    const trendBias = getStableBias(symbol.code, timeframe) * symbol.pipSize * (symbol.code === "XAUUSD" ? 8 : 1);
    const start = Date.now() - limit * timeframeMinutes(timeframe) * 60_000;
    const candles = [];
    let previousClose = basePrice;
    for (let index = 0; index < limit; index += 1) {
        const wave = Math.sin(index / 5) * volatility;
        const microWave = Math.cos(index / 11) * volatility * 0.4;
        const close = basePrice + trendBias * index + wave + microWave;
        const open = previousClose;
        const high = Math.max(open, close) + volatility * 0.45;
        const low = Math.min(open, close) - volatility * 0.45;
        candles.push({
            time: new Date(start + index * timeframeMinutes(timeframe) * 60_000).toISOString(),
            open,
            high,
            low,
            close,
            volume: 1000 + index * 7 + Math.abs(Math.round(wave * 100))
        });
        previousClose = close;
    }
    return candles;
}
function getBasePrice(symbolCode) {
    const basePrices = {
        EURUSD: 1.085,
        GBPUSD: 1.271,
        USDJPY: 157.2,
        GBPJPY: 199.4,
        AUDUSD: 0.665,
        XAUUSD: 2360,
        BTCUSD: 60000
    };
    return basePrices[symbolCode] ?? 1;
}
function getStableBias(symbolCode, timeframe) {
    const value = `${symbolCode}-${timeframe}`
        .split("")
        .reduce((sum, character) => sum + character.charCodeAt(0), 0);
    return (value % 7) - 3;
}
function timeframeMinutes(timeframe) {
    const values = {
        M1: 1,
        M5: 5,
        M15: 15,
        H1: 60,
        H4: 240,
        D1: 1440,
        W1: 10080
    };
    return values[timeframe];
}
function toTwelveDataInterval(timeframe) {
    const values = {
        M1: "1min",
        M5: "5min",
        M15: "15min",
        H1: "1h",
        H4: "4h",
        D1: "1day",
        W1: "1week"
    };
    return values[timeframe];
}
function toTwelveDataSymbol(symbol) {
    if (symbol.code === "XAUUSD") {
        return "XAU/USD";
    }
    if (symbol.code === "BTCUSD") {
        return "BTC/USD";
    }
    const knownSymbol = markets_1.MARKET_SYMBOLS.find((item) => item.code === symbol.code);
    return knownSymbol?.label ?? symbol.label;
}