/** * 🌊 IMMEDIATE WAVE RIDER - LIVE MARKETS 🌊 * * Aβ†’Z ↔ Zβ†’A "They Can't Stop Them All!" * * ╔═══════════════════════════════════════════════════════════════════════════╗ * β•‘ IMMEDIATE ENTRY MODE β•‘ * β•‘ β•‘ * β•‘ β€’ Enter 1 position per broker IMMEDIATELY on first scan β•‘ * β•‘ β€’ Scout positions ride the wave from the start β•‘ * β•‘ β€’ Aβ†’Z on odd cycles, Zβ†’A on even cycles for new entries β•‘ * β•‘ β€’ "They can't stop them all!" β•‘ * β•‘ β•‘ * β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• * * Author: Gary Leckey - R&A Consulting */ import * as dotenv from 'dotenv'; import * as path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); dotenv.config({ path: path.join(__dirname, '..', '.env') }); // ═══════════════════════════════════════════════════════════════════════════ // Configuration // ═══════════════════════════════════════════════════════════════════════════ const CONFIG = { BALANCE_PER_BROKER: 20, POSITION_SIZE_PCT: 0.10, // 10% per trade = Β£2 per position STOP_LOSS_PCT: 0.02, // 2% stop loss TAKE_PROFIT_PCT: 0.04, // 4% take profit MAX_POSITIONS_PER_BROKER: 5, SCAN_INTERVAL_MS: 5000, // 5 seconds SCOUT_ON_FIRST_SCAN: true, // Deploy scouts immediately }; // ═══════════════════════════════════════════════════════════════════════════ // Types // ═══════════════════════════════════════════════════════════════════════════ interface LivePrice { symbol: string; bid: number; ask: number; mid: number; spread: number; change24h?: number; } interface Position { broker: string; symbol: string; direction: 'LONG' | 'SHORT'; size: number; entryPrice: number; currentPrice: number; pnl: number; pnlPercent: number; taxFree: boolean; isScout: boolean; } interface BrokerState { name: string; emoji: string; balance: number; positions: number; wins: number; losses: number; pnl: number; taxFree: boolean; hasScout: boolean; scoutDeployed: boolean; } // ═══════════════════════════════════════════════════════════════════════════ // Real Price Feeds // ═══════════════════════════════════════════════════════════════════════════ // BINANCE - 20 top pairs async function fetchBinancePrices(): Promise { const symbols = [ 'BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'XRPUSDT', 'DOGEUSDT', 'ADAUSDT', 'AVAXUSDT', 'DOTUSDT', 'LINKUSDT', 'MATICUSDT', 'LTCUSDT', 'NEARUSDT', 'UNIUSDT', 'AAVEUSDT', 'APTUSDT', 'ARBUSDT', 'OPUSDT', 'ATOMUSDT', 'SHIBUSDT' ]; try { const response = await fetch('https://api.binance.com/api/v3/ticker/24hr'); if (!response.ok) return []; const data = await response.json(); const prices: LivePrice[] = []; for (const sym of symbols) { const ticker = data.find((t: any) => t.symbol === sym); if (ticker) { const bid = parseFloat(ticker.bidPrice); const ask = parseFloat(ticker.askPrice); prices.push({ symbol: sym, bid, ask, mid: (bid + ask) / 2, spread: ask - bid, change24h: parseFloat(ticker.priceChangePercent) }); } } return prices; } catch { return []; } } // KRAKEN async function fetchKrakenPrices(): Promise { const pairs = 'XXBTZGBP,XETHZGBP,XXBTZUSD,XETHZUSD,SOLUSD,XRPUSD,ADAUSD,DOTUSD,LINKUSD,ATOMUSD'; try { const response = await fetch(`https://api.kraken.com/0/public/Ticker?pair=${pairs}`); if (!response.ok) return []; const data = await response.json(); if (data.error?.length > 0) return []; const prices: LivePrice[] = []; for (const [key, ticker] of Object.entries(data.result) as any) { const bid = parseFloat(ticker.b[0]); const ask = parseFloat(ticker.a[0]); const open = parseFloat(ticker.o); const last = parseFloat(ticker.c[0]); prices.push({ symbol: key, bid, ask, mid: (bid + ask) / 2, spread: ask - bid, change24h: ((last - open) / open) * 100 }); } return prices; } catch { return []; } } // OKX async function fetchOKXPrices(): Promise { const symbols = [ 'BTC-USDT', 'ETH-USDT', 'SOL-USDT', 'XRP-USDT', 'DOGE-USDT', 'ADA-USDT', 'DOT-USDT', 'AVAX-USDT', 'LINK-USDT', 'NEAR-USDT', 'ATOM-USDT', 'UNI-USDT', 'AAVE-USDT', 'LTC-USDT', 'ARB-USDT' ]; try { const response = await fetch('https://www.okx.com/api/v5/market/tickers?instType=SPOT'); if (!response.ok) return []; const data = await response.json(); if (!data.data) return []; const prices: LivePrice[] = []; for (const sym of symbols) { const ticker = data.data.find((t: any) => t.instId === sym); if (ticker) { const bid = parseFloat(ticker.bidPx); const ask = parseFloat(ticker.askPx); const open = parseFloat(ticker.open24h); const last = parseFloat(ticker.last); prices.push({ symbol: sym, bid, ask, mid: (bid + ask) / 2, spread: ask - bid, change24h: ((last - open) / open) * 100 }); } } return prices; } catch { return []; } } // COINBASE async function fetchCoinbasePrices(): Promise { const symbols = ['BTC-GBP', 'ETH-GBP', 'SOL-GBP', 'BTC-USD', 'ETH-USD', 'SOL-USD', 'DOGE-USD', 'ADA-USD']; const prices: LivePrice[] = []; // Fetch in parallel const fetches = symbols.map(async sym => { try { const response = await fetch(`https://api.exchange.coinbase.com/products/${sym}/ticker`); if (response.ok) { const data = await response.json(); const bid = parseFloat(data.bid); const ask = parseFloat(data.ask); return { symbol: sym, bid, ask, mid: (bid + ask) / 2, spread: ask - bid }; } } catch {} return null; }); const results = await Promise.all(fetches); return results.filter(p => p !== null) as LivePrice[]; } // BITSTAMP async function fetchBitstampPrices(): Promise { const symbols = ['btcgbp', 'ethgbp', 'btcusd', 'ethusd', 'xrpusd', 'ltcusd', 'solusd']; const prices: LivePrice[] = []; const fetches = symbols.map(async sym => { try { const response = await fetch(`https://www.bitstamp.net/api/v2/ticker/${sym}/`); if (response.ok) { const data = await response.json(); const bid = parseFloat(data.bid); const ask = parseFloat(data.ask); const open = parseFloat(data.open); const last = parseFloat(data.last); return { symbol: sym.toUpperCase(), bid, ask, mid: (bid + ask) / 2, spread: ask - bid, change24h: ((last - open) / open) * 100 }; } } catch {} return null; }); const results = await Promise.all(fetches); return results.filter(p => p !== null) as LivePrice[]; } // FOREX async function fetchForexPrices(): Promise { try { const response = await fetch('https://api.exchangerate-api.com/v4/latest/USD'); if (!response.ok) return []; const data = await response.json(); const prices: LivePrice[] = []; const pairs = [ { base: 'EUR', symbol: 'EUR/USD' }, { base: 'GBP', symbol: 'GBP/USD' }, { base: 'JPY', symbol: 'USD/JPY' }, { base: 'CHF', symbol: 'USD/CHF' }, { base: 'AUD', symbol: 'AUD/USD' }, { base: 'CAD', symbol: 'USD/CAD' }, { base: 'NZD', symbol: 'NZD/USD' }, { base: 'SGD', symbol: 'USD/SGD' }, ]; for (const pair of pairs) { const rate = data.rates[pair.base]; if (rate) { let mid: number; if (pair.symbol.startsWith('USD/')) { mid = rate; } else { mid = 1 / rate; } const spread = mid * 0.0002; prices.push({ symbol: pair.symbol, bid: mid - spread / 2, ask: mid + spread / 2, mid, spread }); } } return prices; } catch { return []; } } // ═══════════════════════════════════════════════════════════════════════════ // Immediate Wave Rider // ═══════════════════════════════════════════════════════════════════════════ class ImmediateWaveRider { private positions: Map = new Map(); private brokers: Map = new Map(); private scanDirection: 'Aβ†’Z' | 'Zβ†’A' = 'Aβ†’Z'; private scans = 0; private startTime = new Date(); private totalPnL = 0; private wins = 0; private losses = 0; private priceHistory: Map = new Map(); constructor() { this.initBrokers(); } private initBrokers() { const brokerList = [ { name: 'Binance', emoji: 'πŸͺ™', taxFree: false }, { name: 'Kraken', emoji: 'πŸ¦‘', taxFree: false }, { name: 'Coinbase', emoji: '🟠', taxFree: false }, { name: 'Bitstamp', emoji: 'πŸ’Ž', taxFree: false }, { name: 'OKX', emoji: 'β­•', taxFree: false }, { name: 'OANDA', emoji: 'πŸ’±', taxFree: false }, { name: 'FXCM', emoji: 'πŸ’Ή', taxFree: false }, { name: 'IG', emoji: 'πŸ“ˆ', taxFree: true }, { name: 'CMC', emoji: 'πŸ“‰', taxFree: true }, { name: 'Capital', emoji: 'πŸ“Š', taxFree: false }, { name: 'Saxo', emoji: '🏦', taxFree: false }, { name: 'IB', emoji: 'πŸ›οΈ', taxFree: false }, { name: 'Alpaca', emoji: 'πŸ¦™', taxFree: false }, { name: 'Gemini', emoji: 'πŸ’ ', taxFree: false }, ]; for (const b of brokerList) { this.brokers.set(b.name, { name: b.name, emoji: b.emoji, balance: CONFIG.BALANCE_PER_BROKER, positions: 0, wins: 0, losses: 0, pnl: 0, taxFree: b.taxFree, hasScout: false, scoutDeployed: false }); } } async start(): Promise { this.printHeader(); console.log('\n πŸ“‘ Connecting to live markets and deploying scouts...\n'); while (true) { this.scans++; this.scanDirection = this.scanDirection === 'Aβ†’Z' ? 'Zβ†’A' : 'Aβ†’Z'; await this.executeScan(); this.displayStatus(); await new Promise(r => setTimeout(r, CONFIG.SCAN_INTERVAL_MS)); } } private async executeScan(): Promise { // Fetch all prices in parallel const [binance, kraken, okx, coinbase, bitstamp, forex] = await Promise.all([ fetchBinancePrices(), fetchKrakenPrices(), fetchOKXPrices(), fetchCoinbasePrices(), fetchBitstampPrices(), fetchForexPrices() ]); // Sort by direction const sortFn = (a: LivePrice, b: LivePrice) => { const cmp = a.symbol.localeCompare(b.symbol); return this.scanDirection === 'Aβ†’Z' ? cmp : -cmp; }; // Process each exchange - sorted by Aβ†’Z or Zβ†’A this.processPrices('Binance', binance.sort(sortFn)); this.processPrices('Kraken', kraken.sort(sortFn)); this.processPrices('OKX', okx.sort(sortFn)); this.processPrices('Coinbase', coinbase.sort(sortFn)); this.processPrices('Bitstamp', bitstamp.sort(sortFn)); // Forex goes to multiple brokers const sortedForex = forex.sort(sortFn); this.processPrices('OANDA', sortedForex); this.processPrices('FXCM', sortedForex); this.processPrices('IG', sortedForex); this.processPrices('CMC', sortedForex); this.processPrices('Saxo', sortedForex); this.processPrices('Capital', sortedForex); this.processPrices('IB', sortedForex); } private processPrices(broker: string, prices: LivePrice[]): void { const brokerState = this.brokers.get(broker); if (!brokerState || prices.length === 0) return; for (const price of prices) { const key = `${broker}:${price.symbol}`; // Track price history if (!this.priceHistory.has(key)) { this.priceHistory.set(key, []); } const history = this.priceHistory.get(key)!; history.push(price.mid); if (history.length > 50) history.shift(); // Check existing position const existingPos = this.positions.get(key); if (existingPos) { this.updatePosition(key, price.mid); continue; } } // SCOUT DEPLOYMENT: Deploy 1 scout per broker immediately if none exists if (!brokerState.scoutDeployed && prices.length > 0) { // Pick the first asset in sorted order (Aβ†’Z or Zβ†’A direction) const scoutPrice = prices[0]; this.deployScout(broker, scoutPrice); } // Additional entries based on 24h momentum for (const price of prices) { const key = `${broker}:${price.symbol}`; if (this.positions.has(key)) continue; if (brokerState.positions >= CONFIG.MAX_POSITIONS_PER_BROKER) break; // Enter on strong 24h momentum if (price.change24h !== undefined) { if (price.change24h > 3) { // Strong bullish - LONG this.openPosition(broker, price, 'LONG', `πŸ“ˆ+${price.change24h.toFixed(1)}%`, false); } else if (price.change24h < -3) { // Strong bearish - SHORT this.openPosition(broker, price, 'SHORT', `πŸ“‰${price.change24h.toFixed(1)}%`, false); } } } } private deployScout(broker: string, price: LivePrice): void { const brokerState = this.brokers.get(broker); if (!brokerState) return; // Use 24h change to pick direction, or random if not available let direction: 'LONG' | 'SHORT'; if (price.change24h !== undefined) { direction = price.change24h >= 0 ? 'LONG' : 'SHORT'; } else { direction = Math.random() > 0.5 ? 'LONG' : 'SHORT'; } const key = `${broker}:${price.symbol}`; const entryPrice = direction === 'LONG' ? price.ask : price.bid; const size = (brokerState.balance * CONFIG.POSITION_SIZE_PCT) / entryPrice; this.positions.set(key, { broker, symbol: price.symbol, direction, size, entryPrice, currentPrice: price.mid, pnl: 0, pnlPercent: 0, taxFree: brokerState.taxFree, isScout: true }); brokerState.positions++; brokerState.scoutDeployed = true; brokerState.hasScout = true; const dir = this.scanDirection; const dirEmoji = direction === 'LONG' ? '⬆️' : '⬇️'; const taxLabel = brokerState.taxFree ? ' 🎁TAX FREE' : ''; const priceStr = price.mid < 10 ? price.mid.toFixed(5) : price.mid.toFixed(2); console.log(` ${brokerState.emoji} [${dir}] πŸ”­ SCOUT ${dirEmoji}: ${price.symbol} @ ${priceStr}${taxLabel}`); } private openPosition(broker: string, price: LivePrice, direction: 'LONG' | 'SHORT', reason: string, isScout: boolean): void { const brokerState = this.brokers.get(broker); if (!brokerState) return; const key = `${broker}:${price.symbol}`; const entryPrice = direction === 'LONG' ? price.ask : price.bid; const size = (brokerState.balance * CONFIG.POSITION_SIZE_PCT) / entryPrice; this.positions.set(key, { broker, symbol: price.symbol, direction, size, entryPrice, currentPrice: price.mid, pnl: 0, pnlPercent: 0, taxFree: brokerState.taxFree, isScout }); brokerState.positions++; const dir = this.scanDirection; const dirEmoji = direction === 'LONG' ? '⬆️' : '⬇️'; const taxLabel = brokerState.taxFree ? ' 🎁' : ''; const priceStr = price.mid < 10 ? price.mid.toFixed(5) : price.mid.toFixed(2); console.log(` ${brokerState.emoji} [${dir}] ⚑ ${dirEmoji} ${price.symbol} @ ${priceStr} (${reason})${taxLabel}`); } private updatePosition(key: string, currentPrice: number): void { const pos = this.positions.get(key); if (!pos) return; const brokerState = this.brokers.get(pos.broker); if (!brokerState) return; pos.currentPrice = currentPrice; const priceDiff = currentPrice - pos.entryPrice; const multiplier = pos.direction === 'LONG' ? 1 : -1; pos.pnl = priceDiff * pos.size * multiplier; pos.pnlPercent = (priceDiff / pos.entryPrice) * 100 * multiplier; // Check stop loss if (pos.pnlPercent <= -CONFIG.STOP_LOSS_PCT * 100) { this.closePosition(key, 'STOP'); } // Check take profit else if (pos.pnlPercent >= CONFIG.TAKE_PROFIT_PCT * 100) { this.closePosition(key, 'PROFIT'); } } private closePosition(key: string, reason: 'STOP' | 'PROFIT'): void { const pos = this.positions.get(key); if (!pos) return; const brokerState = this.brokers.get(pos.broker); if (!brokerState) return; brokerState.balance += pos.pnl; brokerState.pnl += pos.pnl; this.totalPnL += pos.pnl; if (pos.pnl >= 0) { brokerState.wins++; this.wins++; } else { brokerState.losses++; this.losses++; } brokerState.positions--; if (pos.isScout) brokerState.hasScout = false; const emoji = pos.pnl >= 0 ? 'βœ…' : '❌'; const scoutLabel = pos.isScout ? ' πŸ”­' : ''; const taxLabel = pos.taxFree ? ' 🎁TAX FREE!' : ''; const pnlStr = pos.pnl >= 0 ? `+Β£${pos.pnl.toFixed(4)}` : `-Β£${Math.abs(pos.pnl).toFixed(4)}`; console.log(` ${brokerState.emoji} ${emoji} ${reason}${scoutLabel}: ${pos.symbol} | P&L: ${pnlStr}${taxLabel}`); this.positions.delete(key); } private printHeader(): void { console.log('\n'); console.log(' ╔═══════════════════════════════════════════════════════════════════════════════╗'); console.log(' β•‘ β•‘'); console.log(' β•‘ 🌊 IMMEDIATE WAVE RIDER - LIVE MARKETS 🌊 β•‘'); console.log(' β•‘ β•‘'); console.log(' β•‘ Aβ†’Z ↔ Zβ†’A "They Can\'t Stop Them All!" β•‘'); console.log(' β•‘ β•‘'); console.log(' ╠═══════════════════════════════════════════════════════════════════════════════╣'); console.log(' β•‘ β•‘'); console.log(' β•‘ CRYPTO: πŸͺ™ Binance πŸ¦‘ Kraken 🟠 Coinbase πŸ’Ž Bitstamp πŸ’  Gemini β­• OKX β•‘'); console.log(' β•‘ FOREX: πŸ’± OANDA πŸ’Ή FXCM 🏦 Saxo πŸ›οΈ IB β•‘'); console.log(' β•‘ CFD: πŸ“Š Capital πŸ“ˆ IG πŸ“‰ CMC πŸ¦™ Alpaca β•‘'); console.log(' β•‘ β•‘'); console.log(' β•‘ 🎁 TAX FREE (Spread Betting): πŸ“ˆ IG πŸ“‰ CMC β•‘'); console.log(' β•‘ β•‘'); console.log(' ╠═══════════════════════════════════════════════════════════════════════════════╣'); console.log(` β•‘ Capital: Β£${CONFIG.BALANCE_PER_BROKER} Γ— 14 = Β£${CONFIG.BALANCE_PER_BROKER * 14} | Size: ${CONFIG.POSITION_SIZE_PCT*100}% | SL: ${CONFIG.STOP_LOSS_PCT*100}% | TP: ${CONFIG.TAKE_PROFIT_PCT*100}% β•‘`); console.log(' β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•'); console.log(''); console.log(' πŸ”­ Deploying SCOUTS immediately - 1 per broker in Aβ†’Z / Zβ†’A order...'); console.log(' ────────────────────────────────────────────────────────────────────────────────'); } private displayStatus(): void { const elapsed = Math.floor((Date.now() - this.startTime.getTime()) / 1000); const minutes = Math.floor(elapsed / 60); const seconds = elapsed % 60; let totalBalance = 0; let totalPositions = 0; let scoutsActive = 0; let taxFreePnL = 0; const lines: string[] = []; for (const [name, state] of this.brokers) { totalBalance += state.balance; totalPositions += state.positions; if (state.hasScout) scoutsActive++; if (state.taxFree) taxFreePnL += state.pnl; const hitRate = state.wins + state.losses > 0 ? ((state.wins / (state.wins + state.losses)) * 100).toFixed(0) : '-'; const pnlStr = state.pnl >= 0 ? `+Β£${state.pnl.toFixed(2)}` : `-Β£${Math.abs(state.pnl).toFixed(2)}`; const pnlEmoji = state.pnl >= 0 ? '🟒' : 'πŸ”΄'; const taxLabel = state.taxFree ? '🎁' : ' '; const scoutLabel = state.hasScout ? 'πŸ”­' : ' '; lines.push( ` β”‚ ${state.emoji} ${state.name.padEnd(8)} β”‚ Β£${state.balance.toFixed(2).padStart(6)} β”‚ ${state.positions}/${CONFIG.MAX_POSITIONS_PER_BROKER} β”‚ ${hitRate.padStart(3)}% β”‚ ${pnlEmoji} ${pnlStr.padStart(8)} β”‚ ${taxLabel} β”‚ ${scoutLabel} β”‚` ); } const totalHitRate = this.wins + this.losses > 0 ? ((this.wins / (this.wins + this.losses)) * 100).toFixed(1) : '0.0'; const totalPnLStr = this.totalPnL >= 0 ? `+Β£${this.totalPnL.toFixed(2)}` : `-Β£${Math.abs(this.totalPnL).toFixed(2)}`; const totalEmoji = this.totalPnL >= 0 ? '🟒' : 'πŸ”΄'; console.log(''); console.log(' β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”'); console.log(` β”‚ SCAN #${this.scans.toString().padStart(5)} [${this.scanDirection}] β”‚ Time: ${minutes}m ${seconds}s β”‚ Positions: ${totalPositions}/${14 * CONFIG.MAX_POSITIONS_PER_BROKER} β”‚ πŸ”­ Scouts: ${scoutsActive} β”‚`); console.log(' β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€'); console.log(' β”‚ Broker β”‚ Balance β”‚ Pos β”‚ HR β”‚ P&L β”‚ 🎁 β”‚ πŸ”­ β”‚'); console.log(' β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€'); for (const line of lines) { console.log(line); } console.log(' β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€'); console.log(` β”‚ 🌊 TOTAL β”‚ Β£${totalBalance.toFixed(2).padStart(6)} β”‚ ${totalPositions.toString().padStart(2)} β”‚${totalHitRate.padStart(5)}% β”‚ ${totalEmoji} ${totalPnLStr.padStart(8)} β”‚ β”‚ β”‚`); console.log(' β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜'); if (taxFreePnL !== 0) { const taxFreeStr = taxFreePnL >= 0 ? `+Β£${taxFreePnL.toFixed(4)}` : `-Β£${Math.abs(taxFreePnL).toFixed(4)}`; console.log(` 🎁 Tax-Free P&L (IG + CMC): ${taxFreeStr}`); } this.displayPositions(); } private displayPositions(): void { const allPositions = Array.from(this.positions.values()); if (allPositions.length === 0) { console.log(''); console.log(` 🌊 [${this.scanDirection}] All scouts closed - looking for re-entry opportunities...`); console.log(''); return; } allPositions.sort((a, b) => b.pnl - a.pnl); console.log(''); console.log(` 🌊 Active Positions [${this.scanDirection}]:`); console.log(''); for (const pos of allPositions.slice(0, 16)) { const emoji = pos.pnl >= 0 ? '🟒' : 'πŸ”΄'; const dir = pos.direction === 'LONG' ? '⬆' : '⬇'; const brokerState = this.brokers.get(pos.broker); const brokerEmoji = brokerState?.emoji || 'πŸ“ˆ'; const taxLabel = pos.taxFree ? ' 🎁' : ''; const scoutLabel = pos.isScout ? ' πŸ”­' : ''; const pnlStr = pos.pnl >= 0 ? `+Β£${pos.pnl.toFixed(4)}` : `-Β£${Math.abs(pos.pnl).toFixed(4)}`; console.log(` ${brokerEmoji} ${emoji} ${pos.symbol.padEnd(12)} ${dir} β†’ ${pnlStr} (${pos.pnlPercent.toFixed(2)}%)${taxLabel}${scoutLabel}`); } if (allPositions.length > 16) { console.log(` ... and ${allPositions.length - 16} more positions`); } console.log(''); } } // ═══════════════════════════════════════════════════════════════════════════ // Main // ═══════════════════════════════════════════════════════════════════════════ async function main() { console.log(` ╔═══════════════════════════════════════════════════════════════════════════════╗ β•‘ β•‘ β•‘ 🌊 IMMEDIATE WAVE RIDER 🌊 β•‘ β•‘ β•‘ β•‘ Strategy: β•‘ β•‘ β€’ Deploy SCOUTS immediately - 1 per broker β•‘ β•‘ β€’ Aβ†’Z on odd scans, Zβ†’A on even scans β•‘ β•‘ β€’ Enter additional positions on strong 24h momentum (>Β±3%) β•‘ β•‘ β€’ Ride the wave with 2% SL / 4% TP β•‘ β•‘ β€’ "They can't stop them all!" β•‘ β•‘ β•‘ β•‘ Live Data Sources: β•‘ β•‘ β€’ Binance API (20 pairs) β•‘ β•‘ β€’ Kraken API (10 pairs) β•‘ β•‘ β€’ OKX API (15 pairs) β•‘ β•‘ β€’ Coinbase API (8 pairs) β•‘ β•‘ β€’ Bitstamp API (7 pairs) β•‘ β•‘ β€’ Forex API (8 major pairs) β•‘ β•‘ β•‘ β•‘ Author: Gary Leckey - R&A Consulting β•‘ β•‘ β•‘ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• `); const rider = new ImmediateWaveRider(); process.on('SIGINT', () => { console.log('\n'); console.log(' ────────────────────────────────────────────────────────────────────────────'); console.log(' 🌊 Wave Rider concludes...'); console.log(' ────────────────────────────────────────────────────────────────────────────'); console.log(''); console.log(' "Aβ†’Z ↔ Zβ†’A - The wave rides eternal"'); console.log(''); process.exit(0); }); await rider.start(); } main().catch(console.error);