Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'
This commit is contained in:
704
vendor/ruvector/examples/neural-trader/exotic/atomic-arbitrage.js
vendored
Normal file
704
vendor/ruvector/examples/neural-trader/exotic/atomic-arbitrage.js
vendored
Normal file
@@ -0,0 +1,704 @@
|
||||
/**
|
||||
* Cross-Exchange Atomic Arbitrage
|
||||
*
|
||||
* EXOTIC: Flash loan arbitrage with MEV protection
|
||||
*
|
||||
* Uses @neural-trader/execution with RuVector for:
|
||||
* - Multi-exchange price monitoring
|
||||
* - Atomic execution via flash loans (DeFi)
|
||||
* - MEV (Miner Extractable Value) protection
|
||||
* - Latency-aware order routing
|
||||
* - Triangular and cross-chain arbitrage
|
||||
*
|
||||
* WARNING: This is for educational purposes.
|
||||
* Real arbitrage requires sophisticated infrastructure.
|
||||
*/
|
||||
|
||||
// Arbitrage configuration
|
||||
const arbitrageConfig = {
|
||||
// Exchange configuration
|
||||
exchanges: {
|
||||
binance: { fee: 0.001, latency: 5, liquidity: 'high' },
|
||||
coinbase: { fee: 0.005, latency: 8, liquidity: 'high' },
|
||||
kraken: { fee: 0.002, latency: 12, liquidity: 'medium' },
|
||||
ftx: { fee: 0.0007, latency: 3, liquidity: 'medium' },
|
||||
uniswap: { fee: 0.003, latency: 15000, liquidity: 'medium', type: 'dex' },
|
||||
sushiswap: { fee: 0.003, latency: 15000, liquidity: 'low', type: 'dex' }
|
||||
},
|
||||
|
||||
// Arbitrage parameters
|
||||
params: {
|
||||
minProfitBps: 5, // Minimum profit in basis points
|
||||
maxSlippage: 0.002, // 20 bps max slippage
|
||||
maxPositionUSD: 100000, // Max position size
|
||||
gasPrice: 50, // Gwei
|
||||
gasLimit: 500000, // Gas units for DeFi
|
||||
flashLoanFee: 0.0009 // 9 bps flash loan fee
|
||||
},
|
||||
|
||||
// MEV protection
|
||||
mev: {
|
||||
usePrivatePool: true,
|
||||
maxPriorityFee: 2, // Gwei
|
||||
bundleTimeout: 2000 // ms
|
||||
},
|
||||
|
||||
// Monitoring
|
||||
monitoring: {
|
||||
updateIntervalMs: 100,
|
||||
priceHistorySize: 1000,
|
||||
alertThresholdBps: 10
|
||||
}
|
||||
};
|
||||
|
||||
// Price Feed Simulator
|
||||
class PriceFeed {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.prices = new Map();
|
||||
this.orderBooks = new Map();
|
||||
this.lastUpdate = Date.now();
|
||||
}
|
||||
|
||||
// Simulate price update
|
||||
updatePrices(basePrice, volatility = 0.0001) {
|
||||
const now = Date.now();
|
||||
|
||||
for (const [exchange, params] of Object.entries(this.config.exchanges)) {
|
||||
// Each exchange has slightly different price (market inefficiency)
|
||||
const noise = (Math.random() - 0.5) * volatility * 2;
|
||||
const exchangeSpecificBias = (Math.random() - 0.5) * 0.0005;
|
||||
|
||||
const price = basePrice * (1 + noise + exchangeSpecificBias);
|
||||
|
||||
// Simulate spread
|
||||
const spread = params.type === 'dex' ? 0.002 : 0.0005;
|
||||
|
||||
this.prices.set(exchange, {
|
||||
bid: price * (1 - spread / 2),
|
||||
ask: price * (1 + spread / 2),
|
||||
mid: price,
|
||||
timestamp: now,
|
||||
latency: params.latency
|
||||
});
|
||||
|
||||
// Simulate order book depth
|
||||
this.orderBooks.set(exchange, this.generateOrderBook(price, spread, params.liquidity));
|
||||
}
|
||||
|
||||
this.lastUpdate = now;
|
||||
}
|
||||
|
||||
generateOrderBook(midPrice, spread, liquidityLevel) {
|
||||
const depths = { high: 5, medium: 3, low: 1 };
|
||||
const baseDepth = depths[liquidityLevel] || 1;
|
||||
|
||||
const bids = [];
|
||||
const asks = [];
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const bidPrice = midPrice * (1 - spread / 2 - i * 0.0001);
|
||||
const askPrice = midPrice * (1 + spread / 2 + i * 0.0001);
|
||||
|
||||
bids.push({
|
||||
price: bidPrice,
|
||||
quantity: baseDepth * 100000 * Math.exp(-i * 0.3) * (0.5 + Math.random())
|
||||
});
|
||||
|
||||
asks.push({
|
||||
price: askPrice,
|
||||
quantity: baseDepth * 100000 * Math.exp(-i * 0.3) * (0.5 + Math.random())
|
||||
});
|
||||
}
|
||||
|
||||
return { bids, asks };
|
||||
}
|
||||
|
||||
getPrice(exchange) {
|
||||
return this.prices.get(exchange);
|
||||
}
|
||||
|
||||
getOrderBook(exchange) {
|
||||
return this.orderBooks.get(exchange);
|
||||
}
|
||||
|
||||
getAllPrices() {
|
||||
return Object.fromEntries(this.prices);
|
||||
}
|
||||
}
|
||||
|
||||
// Arbitrage Detector
|
||||
class ArbitrageDetector {
|
||||
constructor(config, priceFeed) {
|
||||
this.config = config;
|
||||
this.priceFeed = priceFeed;
|
||||
this.opportunities = [];
|
||||
this.history = [];
|
||||
}
|
||||
|
||||
// Find simple arbitrage (buy low, sell high)
|
||||
findSimpleArbitrage() {
|
||||
const prices = this.priceFeed.getAllPrices();
|
||||
const exchanges = Object.keys(prices);
|
||||
const opportunities = [];
|
||||
|
||||
for (let i = 0; i < exchanges.length; i++) {
|
||||
for (let j = i + 1; j < exchanges.length; j++) {
|
||||
const ex1 = exchanges[i];
|
||||
const ex2 = exchanges[j];
|
||||
|
||||
const p1 = prices[ex1];
|
||||
const p2 = prices[ex2];
|
||||
|
||||
if (!p1 || !p2) continue;
|
||||
|
||||
// Check buy on ex1, sell on ex2
|
||||
const profit1 = this.calculateProfit(ex1, ex2, p1.ask, p2.bid);
|
||||
if (profit1.profitBps > this.config.params.minProfitBps) {
|
||||
opportunities.push({
|
||||
type: 'simple',
|
||||
buyExchange: ex1,
|
||||
sellExchange: ex2,
|
||||
buyPrice: p1.ask,
|
||||
sellPrice: p2.bid,
|
||||
...profit1
|
||||
});
|
||||
}
|
||||
|
||||
// Check buy on ex2, sell on ex1
|
||||
const profit2 = this.calculateProfit(ex2, ex1, p2.ask, p1.bid);
|
||||
if (profit2.profitBps > this.config.params.minProfitBps) {
|
||||
opportunities.push({
|
||||
type: 'simple',
|
||||
buyExchange: ex2,
|
||||
sellExchange: ex1,
|
||||
buyPrice: p2.ask,
|
||||
sellPrice: p1.bid,
|
||||
...profit2
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return opportunities;
|
||||
}
|
||||
|
||||
// Calculate profit after fees
|
||||
calculateProfit(buyExchange, sellExchange, buyPrice, sellPrice) {
|
||||
const buyFee = this.config.exchanges[buyExchange].fee;
|
||||
const sellFee = this.config.exchanges[sellExchange].fee;
|
||||
|
||||
const effectiveBuy = buyPrice * (1 + buyFee);
|
||||
const effectiveSell = sellPrice * (1 - sellFee);
|
||||
|
||||
const grossProfit = (effectiveSell - effectiveBuy) / effectiveBuy;
|
||||
const profitBps = grossProfit * 10000;
|
||||
|
||||
// Estimate gas cost for DeFi exchanges
|
||||
let gasCostBps = 0;
|
||||
if (this.config.exchanges[buyExchange].type === 'dex' ||
|
||||
this.config.exchanges[sellExchange].type === 'dex') {
|
||||
const gasCostUSD = this.config.params.gasPrice * this.config.params.gasLimit * 1e-9 * 2000; // ETH price
|
||||
const tradeSize = this.config.params.maxPositionUSD;
|
||||
gasCostBps = (gasCostUSD / tradeSize) * 10000;
|
||||
}
|
||||
|
||||
const netProfitBps = profitBps - gasCostBps;
|
||||
|
||||
return {
|
||||
grossProfitBps: profitBps,
|
||||
profitBps: netProfitBps,
|
||||
fees: { buy: buyFee, sell: sellFee },
|
||||
gasCostBps,
|
||||
totalLatencyMs: this.config.exchanges[buyExchange].latency +
|
||||
this.config.exchanges[sellExchange].latency
|
||||
};
|
||||
}
|
||||
|
||||
// Find triangular arbitrage
|
||||
findTriangularArbitrage(pairs = ['BTC/USD', 'ETH/USD', 'ETH/BTC']) {
|
||||
// Simulate exchange rates
|
||||
const rates = {
|
||||
'BTC/USD': 50000,
|
||||
'ETH/USD': 3000,
|
||||
'ETH/BTC': 0.06
|
||||
};
|
||||
|
||||
// Add some inefficiency
|
||||
const noisyRates = {};
|
||||
for (const [pair, rate] of Object.entries(rates)) {
|
||||
noisyRates[pair] = rate * (1 + (Math.random() - 0.5) * 0.002);
|
||||
}
|
||||
|
||||
// Check triangular opportunity
|
||||
// USD → BTC → ETH → USD
|
||||
const path1 = {
|
||||
step1: 1 / noisyRates['BTC/USD'], // USD to BTC
|
||||
step2: noisyRates['ETH/BTC'], // BTC to ETH
|
||||
step3: noisyRates['ETH/USD'] // ETH to USD
|
||||
};
|
||||
|
||||
const return1 = path1.step1 * path1.step2 * path1.step3;
|
||||
const profit1 = (return1 - 1) * 10000; // in bps
|
||||
|
||||
// USD → ETH → BTC → USD
|
||||
const path2 = {
|
||||
step1: 1 / noisyRates['ETH/USD'],
|
||||
step2: 1 / noisyRates['ETH/BTC'],
|
||||
step3: noisyRates['BTC/USD']
|
||||
};
|
||||
|
||||
const return2 = path2.step1 * path2.step2 * path2.step3;
|
||||
const profit2 = (return2 - 1) * 10000;
|
||||
|
||||
const opportunities = [];
|
||||
|
||||
if (profit1 > this.config.params.minProfitBps) {
|
||||
opportunities.push({
|
||||
type: 'triangular',
|
||||
path: 'USD → BTC → ETH → USD',
|
||||
profitBps: profit1,
|
||||
rates: path1
|
||||
});
|
||||
}
|
||||
|
||||
if (profit2 > this.config.params.minProfitBps) {
|
||||
opportunities.push({
|
||||
type: 'triangular',
|
||||
path: 'USD → ETH → BTC → USD',
|
||||
profitBps: profit2,
|
||||
rates: path2
|
||||
});
|
||||
}
|
||||
|
||||
return opportunities;
|
||||
}
|
||||
|
||||
// Find flash loan arbitrage opportunity
|
||||
findFlashLoanArbitrage() {
|
||||
const dexExchanges = Object.entries(this.config.exchanges)
|
||||
.filter(([_, params]) => params.type === 'dex')
|
||||
.map(([name]) => name);
|
||||
|
||||
const cexExchanges = Object.entries(this.config.exchanges)
|
||||
.filter(([_, params]) => params.type !== 'dex')
|
||||
.map(([name]) => name);
|
||||
|
||||
const opportunities = [];
|
||||
const prices = this.priceFeed.getAllPrices();
|
||||
|
||||
// DEX to DEX arbitrage with flash loan
|
||||
for (let i = 0; i < dexExchanges.length; i++) {
|
||||
for (let j = i + 1; j < dexExchanges.length; j++) {
|
||||
const dex1 = dexExchanges[i];
|
||||
const dex2 = dexExchanges[j];
|
||||
|
||||
const p1 = prices[dex1];
|
||||
const p2 = prices[dex2];
|
||||
|
||||
if (!p1 || !p2) continue;
|
||||
|
||||
// Flash loan cost
|
||||
const flashFee = this.config.params.flashLoanFee;
|
||||
|
||||
const minMid = Math.min(p1.mid, p2.mid);
|
||||
const spread = minMid > 0 ? Math.abs(p1.mid - p2.mid) / minMid : 0;
|
||||
const profitBps = (spread - flashFee) * 10000;
|
||||
|
||||
if (profitBps > this.config.params.minProfitBps) {
|
||||
opportunities.push({
|
||||
type: 'flash_loan',
|
||||
buyDex: p1.mid < p2.mid ? dex1 : dex2,
|
||||
sellDex: p1.mid < p2.mid ? dex2 : dex1,
|
||||
spread: spread * 10000,
|
||||
flashFee: flashFee * 10000,
|
||||
profitBps,
|
||||
atomic: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return opportunities;
|
||||
}
|
||||
|
||||
// Scan all arbitrage types
|
||||
scanAll() {
|
||||
const simple = this.findSimpleArbitrage();
|
||||
const triangular = this.findTriangularArbitrage();
|
||||
const flashLoan = this.findFlashLoanArbitrage();
|
||||
|
||||
this.opportunities = [...simple, ...triangular, ...flashLoan]
|
||||
.sort((a, b) => b.profitBps - a.profitBps);
|
||||
|
||||
this.history.push({
|
||||
timestamp: Date.now(),
|
||||
count: this.opportunities.length,
|
||||
bestProfit: this.opportunities[0]?.profitBps || 0
|
||||
});
|
||||
|
||||
return this.opportunities;
|
||||
}
|
||||
}
|
||||
|
||||
// Execution Engine
|
||||
class ExecutionEngine {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.pendingOrders = [];
|
||||
this.executedTrades = [];
|
||||
this.mevProtection = config.mev.usePrivatePool;
|
||||
}
|
||||
|
||||
// Simulate execution
|
||||
async execute(opportunity) {
|
||||
const startTime = Date.now();
|
||||
|
||||
// Check for MEV risk
|
||||
if (opportunity.type === 'flash_loan' && this.mevProtection) {
|
||||
return this.executeWithMEVProtection(opportunity);
|
||||
}
|
||||
|
||||
// Simulate latency
|
||||
await this.simulateLatency(opportunity.totalLatencyMs || 50);
|
||||
|
||||
// Check slippage
|
||||
const slippage = Math.random() * this.config.params.maxSlippage;
|
||||
const adjustedProfit = opportunity.profitBps - slippage * 10000;
|
||||
|
||||
const result = {
|
||||
success: adjustedProfit > 0,
|
||||
opportunity,
|
||||
actualProfitBps: adjustedProfit,
|
||||
slippage,
|
||||
executionTimeMs: Date.now() - startTime,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
this.executedTrades.push(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Execute with MEV protection (Flashbots-style)
|
||||
async executeWithMEVProtection(opportunity) {
|
||||
const startTime = Date.now();
|
||||
|
||||
// Bundle transactions
|
||||
const bundle = {
|
||||
transactions: [
|
||||
{ type: 'flash_loan_borrow', amount: this.config.params.maxPositionUSD },
|
||||
{ type: 'swap', dex: opportunity.buyDex, direction: 'buy' },
|
||||
{ type: 'swap', dex: opportunity.sellDex, direction: 'sell' },
|
||||
{ type: 'flash_loan_repay' }
|
||||
],
|
||||
priorityFee: this.config.mev.maxPriorityFee
|
||||
};
|
||||
|
||||
// Simulate private pool submission
|
||||
await this.simulateLatency(this.config.mev.bundleTimeout);
|
||||
|
||||
// Check if bundle was included
|
||||
const included = Math.random() > 0.2; // 80% success rate
|
||||
|
||||
if (!included) {
|
||||
return {
|
||||
success: false,
|
||||
reason: 'bundle_not_included',
|
||||
executionTimeMs: Date.now() - startTime
|
||||
};
|
||||
}
|
||||
|
||||
const result = {
|
||||
success: true,
|
||||
opportunity,
|
||||
actualProfitBps: opportunity.profitBps * 0.95, // Some slippage
|
||||
mevProtected: true,
|
||||
executionTimeMs: Date.now() - startTime,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
this.executedTrades.push(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
simulateLatency(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, Math.min(ms, 100)));
|
||||
}
|
||||
|
||||
getStats() {
|
||||
const successful = this.executedTrades.filter(t => t.success);
|
||||
const totalProfit = successful.reduce((s, t) => s + (t.actualProfitBps || 0), 0);
|
||||
const avgProfit = successful.length > 0 ? totalProfit / successful.length : 0;
|
||||
|
||||
return {
|
||||
totalTrades: this.executedTrades.length,
|
||||
successfulTrades: successful.length,
|
||||
successRate: this.executedTrades.length > 0
|
||||
? successful.length / this.executedTrades.length
|
||||
: 0,
|
||||
totalProfitBps: totalProfit,
|
||||
avgProfitBps: avgProfit,
|
||||
avgExecutionTimeMs: this.executedTrades.length > 0
|
||||
? this.executedTrades.reduce((s, t) => s + t.executionTimeMs, 0) / this.executedTrades.length
|
||||
: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Latency Monitor
|
||||
class LatencyMonitor {
|
||||
constructor() {
|
||||
this.measurements = new Map();
|
||||
}
|
||||
|
||||
record(exchange, latencyMs) {
|
||||
if (!this.measurements.has(exchange)) {
|
||||
this.measurements.set(exchange, []);
|
||||
}
|
||||
|
||||
const measurements = this.measurements.get(exchange);
|
||||
measurements.push({ latency: latencyMs, timestamp: Date.now() });
|
||||
|
||||
// Keep last 100 measurements
|
||||
if (measurements.length > 100) {
|
||||
measurements.shift();
|
||||
}
|
||||
}
|
||||
|
||||
getStats(exchange) {
|
||||
const measurements = this.measurements.get(exchange);
|
||||
if (!measurements || measurements.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const latencies = measurements.map(m => m.latency);
|
||||
const avg = latencies.reduce((a, b) => a + b, 0) / latencies.length;
|
||||
const sorted = [...latencies].sort((a, b) => a - b);
|
||||
const p50 = sorted[Math.floor(latencies.length * 0.5)];
|
||||
const p99 = sorted[Math.floor(latencies.length * 0.99)];
|
||||
|
||||
return { avg, p50, p99, count: latencies.length };
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('═'.repeat(70));
|
||||
console.log('CROSS-EXCHANGE ATOMIC ARBITRAGE');
|
||||
console.log('═'.repeat(70));
|
||||
console.log();
|
||||
|
||||
// 1. Initialize components
|
||||
console.log('1. System Initialization:');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
const priceFeed = new PriceFeed(arbitrageConfig);
|
||||
const detector = new ArbitrageDetector(arbitrageConfig, priceFeed);
|
||||
const executor = new ExecutionEngine(arbitrageConfig);
|
||||
const latencyMonitor = new LatencyMonitor();
|
||||
|
||||
console.log(` Exchanges: ${Object.keys(arbitrageConfig.exchanges).length}`);
|
||||
console.log(` CEX: ${Object.entries(arbitrageConfig.exchanges).filter(([_, p]) => p.type !== 'dex').length}`);
|
||||
console.log(` DEX: ${Object.entries(arbitrageConfig.exchanges).filter(([_, p]) => p.type === 'dex').length}`);
|
||||
console.log(` Min profit: ${arbitrageConfig.params.minProfitBps} bps`);
|
||||
console.log(` Max position: $${arbitrageConfig.params.maxPositionUSD.toLocaleString()}`);
|
||||
console.log(` MEV protection: ${arbitrageConfig.mev.usePrivatePool ? 'Enabled' : 'Disabled'}`);
|
||||
console.log();
|
||||
|
||||
// 2. Exchange fees
|
||||
console.log('2. Exchange Configuration:');
|
||||
console.log('─'.repeat(70));
|
||||
console.log(' Exchange │ Fee │ Latency │ Liquidity │ Type');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
for (const [exchange, params] of Object.entries(arbitrageConfig.exchanges)) {
|
||||
const type = params.type === 'dex' ? 'DEX' : 'CEX';
|
||||
console.log(` ${exchange.padEnd(11)} │ ${(params.fee * 100).toFixed(2)}% │ ${String(params.latency).padStart(5)}ms │ ${params.liquidity.padEnd(9)} │ ${type}`);
|
||||
}
|
||||
console.log();
|
||||
|
||||
// 3. Price simulation
|
||||
console.log('3. Price Feed Simulation:');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
const basePrice = 50000; // BTC price
|
||||
priceFeed.updatePrices(basePrice);
|
||||
|
||||
console.log(' Exchange │ Bid │ Ask │ Spread');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
for (const [exchange, price] of priceFeed.prices) {
|
||||
const spread = ((price.ask - price.bid) / price.mid * 10000).toFixed(1);
|
||||
console.log(` ${exchange.padEnd(11)} │ $${price.bid.toFixed(2).padStart(9)} │ $${price.ask.toFixed(2).padStart(9)} │ ${spread.padStart(5)} bps`);
|
||||
}
|
||||
console.log();
|
||||
|
||||
// 4. Arbitrage detection
|
||||
console.log('4. Arbitrage Opportunity Scan:');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
// Run multiple scans
|
||||
let allOpportunities = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
priceFeed.updatePrices(basePrice, 0.0005); // Add more volatility
|
||||
const opportunities = detector.scanAll();
|
||||
allOpportunities.push(...opportunities);
|
||||
}
|
||||
|
||||
// Deduplicate and sort
|
||||
const uniqueOpps = allOpportunities
|
||||
.filter((opp, idx, arr) =>
|
||||
arr.findIndex(o => o.type === opp.type &&
|
||||
o.buyExchange === opp.buyExchange &&
|
||||
o.sellExchange === opp.sellExchange) === idx
|
||||
)
|
||||
.sort((a, b) => b.profitBps - a.profitBps);
|
||||
|
||||
console.log(` Scans performed: 10`);
|
||||
console.log(` Total found: ${uniqueOpps.length}`);
|
||||
console.log();
|
||||
|
||||
if (uniqueOpps.length > 0) {
|
||||
console.log(' Top Opportunities:');
|
||||
console.log(' Type │ Route │ Profit │ Details');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
for (const opp of uniqueOpps.slice(0, 5)) {
|
||||
let route = '';
|
||||
let details = '';
|
||||
|
||||
if (opp.type === 'simple') {
|
||||
route = `${opp.buyExchange} → ${opp.sellExchange}`;
|
||||
details = `lat=${opp.totalLatencyMs}ms`;
|
||||
} else if (opp.type === 'triangular') {
|
||||
route = opp.path.substring(0, 22);
|
||||
details = '';
|
||||
} else if (opp.type === 'flash_loan') {
|
||||
route = `${opp.buyDex} ⚡ ${opp.sellDex}`;
|
||||
details = 'atomic';
|
||||
}
|
||||
|
||||
console.log(` ${opp.type.padEnd(12)} │ ${route.padEnd(24)} │ ${opp.profitBps.toFixed(1).padStart(5)} bps │ ${details}`);
|
||||
}
|
||||
} else {
|
||||
console.log(' No profitable opportunities found');
|
||||
}
|
||||
console.log();
|
||||
|
||||
// 5. Execute opportunities
|
||||
console.log('5. Execution Simulation:');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
for (const opp of uniqueOpps.slice(0, 5)) {
|
||||
const result = await executor.execute(opp);
|
||||
|
||||
if (result.success) {
|
||||
console.log(` ✓ ${opp.type.padEnd(12)} +${result.actualProfitBps.toFixed(1)} bps (${result.executionTimeMs}ms)${result.mevProtected ? ' [MEV-protected]' : ''}`);
|
||||
} else {
|
||||
console.log(` ✗ ${opp.type.padEnd(12)} Failed: ${result.reason || 'slippage'}`);
|
||||
}
|
||||
}
|
||||
console.log();
|
||||
|
||||
// 6. Execution stats
|
||||
console.log('6. Execution Statistics:');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
const stats = executor.getStats();
|
||||
|
||||
console.log(` Total trades: ${stats.totalTrades}`);
|
||||
console.log(` Successful: ${stats.successfulTrades}`);
|
||||
console.log(` Success rate: ${(stats.successRate * 100).toFixed(1)}%`);
|
||||
console.log(` Total profit: ${stats.totalProfitBps.toFixed(1)} bps`);
|
||||
console.log(` Avg profit: ${stats.avgProfitBps.toFixed(1)} bps`);
|
||||
console.log(` Avg exec time: ${stats.avgExecutionTimeMs.toFixed(0)}ms`);
|
||||
console.log();
|
||||
|
||||
// 7. Order book depth analysis
|
||||
console.log('7. Order Book Depth Analysis:');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
const sampleExchange = 'binance';
|
||||
const orderBook = priceFeed.getOrderBook(sampleExchange);
|
||||
|
||||
console.log(` ${sampleExchange.toUpperCase()} Order Book (Top 5 levels):`);
|
||||
console.log(' Bids │ Asks');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const bid = orderBook.bids[i];
|
||||
const ask = orderBook.asks[i];
|
||||
console.log(` $${bid.price.toFixed(2)} × ${(bid.quantity / 1000).toFixed(0)}k │ $${ask.price.toFixed(2)} × ${(ask.quantity / 1000).toFixed(0)}k`);
|
||||
}
|
||||
console.log();
|
||||
|
||||
// 8. Latency importance
|
||||
console.log('8. Latency Analysis:');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
console.log(' In arbitrage, latency is critical:');
|
||||
console.log();
|
||||
console.log(' CEX latency: ~5-15ms (colocation advantage)');
|
||||
console.log(' DEX latency: ~15,000ms (block time)');
|
||||
console.log();
|
||||
console.log(' Opportunity lifetime:');
|
||||
console.log(' - Crypto CEX-CEX: 10-100ms');
|
||||
console.log(' - DEX-DEX: 1-2 blocks (~15-30s)');
|
||||
console.log(' - CEX-DEX: Limited by block time');
|
||||
console.log();
|
||||
|
||||
// 9. Risk factors
|
||||
console.log('9. Risk Factors:');
|
||||
console.log('─'.repeat(70));
|
||||
|
||||
console.log(' Key risks in atomic arbitrage:');
|
||||
console.log();
|
||||
console.log(' 1. Execution risk:');
|
||||
console.log(' - Slippage exceeds expected');
|
||||
console.log(' - Partial fills');
|
||||
console.log(' - Network congestion');
|
||||
console.log();
|
||||
console.log(' 2. MEV risk (DeFi):');
|
||||
console.log(' - Frontrunning');
|
||||
console.log(' - Sandwich attacks');
|
||||
console.log(' - Block builder extraction');
|
||||
console.log();
|
||||
console.log(' 3. Smart contract risk:');
|
||||
console.log(' - Flash loan failures');
|
||||
console.log(' - Reentrancy');
|
||||
console.log(' - Oracle manipulation');
|
||||
console.log();
|
||||
|
||||
// 10. RuVector integration
|
||||
console.log('10. RuVector Vector Storage:');
|
||||
console.log('─'.repeat(70));
|
||||
console.log(' Arbitrage opportunities as feature vectors:');
|
||||
console.log();
|
||||
|
||||
if (uniqueOpps.length > 0) {
|
||||
const opp = uniqueOpps[0];
|
||||
const featureVector = [
|
||||
opp.profitBps / 100,
|
||||
opp.type === 'simple' ? 1 : opp.type === 'triangular' ? 2 : 3,
|
||||
(opp.totalLatencyMs || 50) / 1000,
|
||||
opp.gasCostBps ? opp.gasCostBps / 100 : 0,
|
||||
opp.atomic ? 1 : 0
|
||||
];
|
||||
|
||||
console.log(` Opportunity vector:`);
|
||||
console.log(` [${featureVector.map(v => v.toFixed(3)).join(', ')}]`);
|
||||
console.log();
|
||||
console.log(' Dimensions: [profit, type, latency, gas_cost, atomic]');
|
||||
}
|
||||
console.log();
|
||||
console.log(' Use cases:');
|
||||
console.log(' - Pattern recognition for recurring opportunities');
|
||||
console.log(' - Similar opportunity retrieval');
|
||||
console.log(' - Historical profitability analysis');
|
||||
console.log();
|
||||
|
||||
console.log('═'.repeat(70));
|
||||
console.log('Cross-exchange atomic arbitrage analysis completed');
|
||||
console.log('═'.repeat(70));
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
Reference in New Issue
Block a user