skills/crypto-arbitrage/index.ts · 核心套利逻辑
import { Skill } from '@openclaw/core';
import { PolymarketClient } from './clients/polymarket';
import { KalshiClient } from './clients/kalshi';
import { BinanceClient } from './clients/binance';
interface ArbitrageOpportunity {
market: string;
platform1: { name: string; price: number; volume: number };
platform2: { name: string; price: number; volume: number };
spread: number;
expectedProfit: number;
risk: 'low' | 'medium' | 'high';
}
export const cryptoArbitrageSkill = new Skill({
name: 'crypto-arbitrage',
description: '实时监控多个预测市场和加密交易所,自动执行套利交易',
config: {
checkInterval: 5000,
minSpread: 0.03,
maxSlippage: 0.02,
positionSize: 0.05,
stopLoss: 0.10,
},
onStart: async (context) => {
context.logger.info('🚀 启动套利机器人...');
const polymarket = new PolymarketClient(process.env.POLYMARKET_API_KEY);
const kalshi = new KalshiClient(process.env.KALSHI_API_KEY);
const binance = new BinanceClient(process.env.BINANCE_API_KEY);
while (context.isRunning) {
try {
const [polyPrices, kalshiPrices, binancePrices] = await Promise.all([
polymarket.getActiveMarkets(),
kalshi.getActiveMarkets(),
binance.getTickers()
]);
const opportunities = findArbitrageOpportunities({
polyPrices,
kalshiPrices,
binancePrices,
minSpread: context.config.minSpread
});
opportunities.sort((a, b) => b.expectedProfit - a.expectedProfit);
for (const opp of opportunities.slice(0, 3)) {
await executeArbitrage(opp, context);
}
context.logger.info(`✅ 本轮发现 ${opportunities.length} 个机会,执行 ${Math.min(opportunities.length, 3)} 笔交易`);
} catch (error) {
context.logger.error('❌ 监控循环出错:', error);
await context.notify('telegram', {
message: `⚠️ 套利机器人异常:${error.message}`,
level: 'high'
});
}
await sleep(context.config.checkInterval);
}
},
onStop: async (context) => {
context.logger.info('🛑 停止套利机器人,平掉所有仓位...');
await closeAllPositions();
}
});
function findArbitrageOpportunities(data: {
polyPrices: any[];
kalshiPrices: any[];
binancePrices: any[];
minSpread: number;
}): ArbitrageOpportunity[] {
const opportunities: ArbitrageOpportunity[] = [];
for (const polyMarket of data.polyPrices) {
const matchingKalshi = data.kalshiPrices.find(
k => k.eventId === polyMarket.eventId
);
if (matchingKalshi) {
const spread = Math.abs(polyMarket.price - matchingKalshi.price) /
Math.min(polyMarket.price, matchingKalshi.price);
if (spread >= data.minSpread) {
opportunities.push({
market: polyMarket.eventName,
platform1: {
name: 'Polymarket',
price: polyMarket.price,
volume: polyMarket.volume
},
platform2: {
name: 'Kalshi',
price: matchingKalshi.price,
volume: matchingKalshi.volume
},
spread: spread * 100,
expectedProfit: calculateExpectedProfit(spread, polyMarket.volume),
risk: assessRisk(polyMarket, matchingKalshi)
});
}
}
}
return opportunities;
}
async function executeArbitrage(
opp: ArbitrageOpportunity,
context: any
) {
context.logger.info(`🎯 执行套利:${opp.market}, 价差 ${opp.spread.toFixed(2)}%`);
const buyPlatform = opp.platform1.price < opp.platform2.price ?
opp.platform1 : opp.platform2;
const sellPlatform = buyPlatform === opp.platform1 ?
opp.platform2 : opp.platform1;
try {
const [buyResult, sellResult] = await Promise.all([
executeBuy(buyPlatform.name, opp.market, context.config.positionSize),
executeSell(sellPlatform.name, opp.market, context.config.positionSize)
]);
const profit = sellResult.amount - buyResult.amount;
context.logger.info(`✅ 套利完成,利润:$${profit.toFixed(2)}`);
await context.notify('telegram', {
message: `💰 套利成功\n市场:${opp.market}\n价差:${opp.spread.toFixed(2)}%\n利润:$${profit.toFixed(2)}`,
level: 'info'
});
} catch (error) {
context.logger.error('❌ 套利执行失败:', error);
await handleExecutionError(error, opp, context);
}
}
config/arbitrage.json · 参数配置
{
"apiKeys": {
"polymarket": "${POLYMARKET_API_KEY}",
"kalshi": "${KALSHI_API_KEY}",
"binance": "${BINANCE_API_KEY}",
"okx": "${OKX_API_KEY}"
},
"strategy": {
"checkIntervalMs": 5000,
"minSpreadPercent": 3.0,
"maxSlippagePercent": 2.0,
"positionSizePercent": 5.0,
"stopLossPercent": 10.0,
"takeProfitPercent": 20.0,
"maxConcurrentTrades": 5,
"maxDailyTrades": 100
},
"riskManagement": {
"maxTotalExposure": 50.0,
"maxSingleMarketExposure": 10.0,
"correlationThreshold": 0.7,
"emergencyStop": true
},
"notifications": {
"telegram": {
"enabled": true,
"botToken": "${TELEGRAM_BOT_TOKEN}",
"chatId": "${TELEGRAM_CHAT_ID}"
},
"email": {
"enabled": true,
"smtpServer": "smtp.gmail.com",
"from": "${EMAIL_FROM}",
"to": ["${EMAIL_TO}"]
}
}
}