第七章:高级功能与应用
本章将介绍 CCXT 的高级应用场景,包括多交易所套利、量化交易策略、投资组合管理和风险控制系统的实现。
🔄 多交易所套利
套利机会检测器
javascript
class ArbitrageDetector {
constructor(exchanges, config = {}) {
this.exchanges = exchanges;
this.minProfitThreshold = config.minProfitThreshold || 0.5; // 0.5%
this.maxSpreadThreshold = config.maxSpreadThreshold || 5.0; // 5%
this.symbols = config.symbols || ['BTC/USDT', 'ETH/USDT'];
this.opportunities = [];
this.isRunning = false;
}
// 开始检测套利机会
async startDetection(interval = 30000) {
console.log('🔍 开始多交易所套利检测...\n');
this.isRunning = true;
while (this.isRunning) {
try {
for (const symbol of this.symbols) {
await this.detectArbitrageOpportunities(symbol);
await this.sleep(1000); // 避免频率限制
}
// 显示最佳机会
this.displayTopOpportunities();
await this.sleep(interval);
} catch (error) {
console.error('❌ 套利检测错误:', error.message);
await this.sleep(5000);
}
}
}
// 检测特定交易对的套利机会
async detectArbitrageOpportunities(symbol) {
const tickers = await this.fetchAllTickers(symbol);
if (tickers.length < 2) {
console.warn(`⚠️ ${symbol} 可用交易所数量不足`);
return;
}
// 检查所有交易所对之间的价差
for (let i = 0; i < tickers.length; i++) {
for (let j = i + 1; j < tickers.length; j++) {
const opportunity = this.calculateArbitrage(tickers[i], tickers[j], symbol);
if (opportunity && opportunity.profitPercent >= this.minProfitThreshold) {
this.recordOpportunity(opportunity);
}
}
}
}
// 获取所有交易所的行情
async fetchAllTickers(symbol) {
const tickers = [];
const promises = this.exchanges.map(async exchange => {
try {
if (exchange.symbols.includes(symbol)) {
const ticker = await exchange.fetchTicker(symbol);
return {
exchange: exchange.id,
ticker,
timestamp: Date.now(),
};
}
} catch (error) {
console.warn(`⚠️ 获取 ${exchange.id} ${symbol} 行情失败: ${error.message}`);
return null;
}
});
const results = await Promise.all(promises);
return results.filter(result => result !== null);
}
// 计算套利机会
calculateArbitrage(ticker1, ticker2, symbol) {
const buy = ticker1.ticker.ask < ticker2.ticker.ask ? ticker1 : ticker2;
const sell = ticker1.ticker.bid > ticker2.ticker.bid ? ticker1 : ticker2;
if (buy.exchange === sell.exchange) return null;
const buyPrice = buy.ticker.ask;
const sellPrice = sell.ticker.bid;
if (sellPrice <= buyPrice) return null;
const profit = sellPrice - buyPrice;
const profitPercent = (profit / buyPrice) * 100;
// 检查价差合理性
const spread = (sell.ticker.ask - sell.ticker.bid) / sell.ticker.bid * 100;
if (spread > this.maxSpreadThreshold) return null;
// 估算最大交易量(取两边较小的)
const maxVolume = Math.min(
buy.ticker.askVolume || 0,
sell.ticker.bidVolume || 0
);
return {
symbol,
buyExchange: buy.exchange,
sellExchange: sell.exchange,
buyPrice,
sellPrice,
profit,
profitPercent,
maxVolume,
timestamp: Date.now(),
spread: spread,
};
}
// 记录套利机会
recordOpportunity(opportunity) {
// 检查是否已存在相似机会
const existing = this.opportunities.find(opp =>
opp.symbol === opportunity.symbol &&
opp.buyExchange === opportunity.buyExchange &&
opp.sellExchange === opportunity.sellExchange &&
Date.now() - opp.timestamp < 60000 // 1分钟内
);
if (existing) {
// 更新现有机会
Object.assign(existing, opportunity);
} else {
// 添加新机会
this.opportunities.push(opportunity);
// 显示新发现的机会
console.log(`🚀 发现套利机会!`);
this.displayOpportunity(opportunity);
}
// 限制历史记录数量
if (this.opportunities.length > 100) {
this.opportunities = this.opportunities.slice(-100);
}
}
// 显示单个套利机会
displayOpportunity(opp) {
console.log(`💰 ${opp.symbol}:`);
console.log(` 买入: ${opp.buyExchange} @ $${opp.buyPrice.toFixed(2)}`);
console.log(` 卖出: ${opp.sellExchange} @ $${opp.sellPrice.toFixed(2)}`);
console.log(` 利润: $${opp.profit.toFixed(2)} (${opp.profitPercent.toFixed(2)}%)`);
console.log(` 最大量: ${opp.maxVolume.toFixed(4)}`);
console.log(` 价差: ${opp.spread.toFixed(4)}%\n`);
}
// 显示最佳套利机会
displayTopOpportunities(limit = 5) {
const recent = this.opportunities
.filter(opp => Date.now() - opp.timestamp < 300000) // 5分钟内
.sort((a, b) => b.profitPercent - a.profitPercent)
.slice(0, limit);
if (recent.length === 0) {
console.log('📭 暂无套利机会');
return;
}
console.log(`🏆 最佳套利机会 (Top ${recent.length}):`);
console.log('='.repeat(60));
recent.forEach((opp, index) => {
console.log(`${index + 1}. ${opp.symbol} | ${opp.profitPercent.toFixed(2)}% | ${opp.buyExchange}→${opp.sellExchange}`);
});
console.log('='.repeat(60) + '\n');
}
// 获取套利统计
getArbitrageStats() {
const now = Date.now();
const recent = this.opportunities.filter(opp => now - opp.timestamp < 3600000); // 1小时内
if (recent.length === 0) return null;
const stats = {
totalOpportunities: recent.length,
avgProfitPercent: recent.reduce((sum, opp) => sum + opp.profitPercent, 0) / recent.length,
maxProfitPercent: Math.max(...recent.map(opp => opp.profitPercent)),
symbolStats: {},
exchangeStats: {},
};
// 按交易对统计
recent.forEach(opp => {
if (!stats.symbolStats[opp.symbol]) {
stats.symbolStats[opp.symbol] = { count: 0, avgProfit: 0 };
}
stats.symbolStats[opp.symbol].count++;
stats.symbolStats[opp.symbol].avgProfit += opp.profitPercent;
});
// 计算平均值
Object.keys(stats.symbolStats).forEach(symbol => {
stats.symbolStats[symbol].avgProfit /= stats.symbolStats[symbol].count;
});
return stats;
}
// 停止检测
stop() {
this.isRunning = false;
console.log('⏹️ 停止套利检测');
}
async sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// 使用示例
async function arbitrageExample() {
// 初始化多个交易所
const exchanges = [
new ccxt.binance({ enableRateLimit: true }),
new ccxt.coinbasepro({ enableRateLimit: true }),
new ccxt.kraken({ enableRateLimit: true }),
];
// 加载市场数据
await Promise.all(exchanges.map(exchange => exchange.loadMarkets()));
const detector = new ArbitrageDetector(exchanges, {
minProfitThreshold: 0.3, // 0.3%
symbols: ['BTC/USDT', 'ETH/USDT', 'BNB/USDT'],
});
// 开始检测(运行30秒后停止)
setTimeout(() => detector.stop(), 30000);
await detector.startDetection(10000); // 每10秒检测一次
}
// arbitrageExample();
📊 量化交易策略
移动平均线交叉策略
javascript
class MovingAverageCrossStrategy {
constructor(exchange, config = {}) {
this.exchange = exchange;
this.symbol = config.symbol || 'BTC/USDT';
this.fastPeriod = config.fastPeriod || 5;
this.slowPeriod = config.slowPeriod || 20;
this.timeframe = config.timeframe || '1h';
this.positionSize = config.positionSize || 0.01; // BTC
this.position = 0; // 当前持仓:1=多头,-1=空头,0=无持仓
this.priceHistory = [];
this.signals = [];
this.trades = [];
this.isRunning = false;
}
// 开始策略执行
async start() {
console.log(`📈 启动移动平均线交叉策略: ${this.symbol}`);
console.log(`配置: 快线=${this.fastPeriod}, 慢线=${this.slowPeriod}, 周期=${this.timeframe}\n`);
this.isRunning = true;
// 初始加载历史数据
await this.loadHistoricalData();
// 开始实时监控
while (this.isRunning) {
try {
await this.updateData();
await this.checkSignals();
await this.sleep(60000); // 每分钟检查一次
} catch (error) {
console.error('❌ 策略执行错误:', error.message);
await this.sleep(5000);
}
}
}
// 加载历史数据
async loadHistoricalData() {
try {
const limit = Math.max(this.slowPeriod * 2, 100);
const ohlcv = await this.exchange.fetchOHLCV(this.symbol, this.timeframe, undefined, limit);
this.priceHistory = ohlcv.map(candle => ({
timestamp: candle[0],
open: candle[1],
high: candle[2],
low: candle[3],
close: candle[4],
volume: candle[5],
}));
console.log(`✅ 加载历史数据: ${this.priceHistory.length} 根K线`);
} catch (error) {
console.error('❌ 加载历史数据失败:', error.message);
throw error;
}
}
// 更新最新数据
async updateData() {
const ticker = await this.exchange.fetchTicker(this.symbol);
const now = Date.now();
// 更新最新价格(简化处理,实际应该基于K线)
const latestPrice = {
timestamp: now,
close: ticker.last,
volume: ticker.baseVolume,
};
// 如果是新的时间周期,添加新数据点
if (this.priceHistory.length === 0 ||
now - this.priceHistory[this.priceHistory.length - 1].timestamp > this.getTimeframeMs()) {
this.priceHistory.push(latestPrice);
// 限制历史数据数量
if (this.priceHistory.length > 200) {
this.priceHistory = this.priceHistory.slice(-200);
}
} else {
// 更新最后一个数据点
this.priceHistory[this.priceHistory.length - 1] = latestPrice;
}
}
// 检查交易信号
async checkSignals() {
if (this.priceHistory.length < this.slowPeriod) {
return; // 数据不足
}
// 计算移动平均线
const fastMA = this.calculateSMA(this.fastPeriod);
const slowMA = this.calculateSMA(this.slowPeriod);
if (fastMA.length < 2 || slowMA.length < 2) {
return; // 数据不足
}
const currentFast = fastMA[fastMA.length - 1];
const currentSlow = slowMA[slowMA.length - 1];
const prevFast = fastMA[fastMA.length - 2];
const prevSlow = slowMA[slowMA.length - 2];
const currentPrice = this.priceHistory[this.priceHistory.length - 1].close;
// 检测金叉和死叉
let signal = null;
if (prevFast <= prevSlow && currentFast > currentSlow) {
signal = 'buy'; // 金叉
} else if (prevFast >= prevSlow && currentFast < currentSlow) {
signal = 'sell'; // 死叉
}
if (signal) {
await this.processSignal(signal, currentPrice, {
fastMA: currentFast,
slowMA: currentSlow,
});
}
// 显示当前状态
this.displayCurrentStatus(currentPrice, currentFast, currentSlow);
}
// 处理交易信号
async processSignal(signal, price, indicators) {
const timestamp = Date.now();
console.log(`🎯 交易信号: ${signal.toUpperCase()}`);
console.log(`价格: $${price.toFixed(2)}`);
console.log(`快线: $${indicators.fastMA.toFixed(2)}`);
console.log(`慢线: $${indicators.slowMA.toFixed(2)}`);
// 记录信号
this.signals.push({
timestamp,
signal,
price,
indicators,
});
// 执行交易
if (signal === 'buy' && this.position <= 0) {
await this.executeBuy(price);
} else if (signal === 'sell' && this.position >= 0) {
await this.executeSell(price);
}
}
// 执行买入
async executeBuy(price) {
try {
console.log(`🟢 执行买入: ${this.positionSize} ${this.symbol.split('/')[0]} @ $${price.toFixed(2)}`);
// 这里应该实际执行买入订单
// const order = await this.exchange.createMarketBuyOrder(this.symbol, this.positionSize);
// 模拟执行
const trade = {
timestamp: Date.now(),
side: 'buy',
amount: this.positionSize,
price: price,
cost: this.positionSize * price,
id: `sim_${Date.now()}`,
};
this.trades.push(trade);
this.position = 1; // 设置为多头
console.log(`✅ 买入成功,持仓: ${this.position > 0 ? '多头' : '空头'}\n`);
} catch (error) {
console.error('❌ 买入失败:', error.message);
}
}
// 执行卖出
async executeSell(price) {
try {
console.log(`🔴 执行卖出: ${this.positionSize} ${this.symbol.split('/')[0]} @ $${price.toFixed(2)}`);
// 这里应该实际执行卖出订单
// const order = await this.exchange.createMarketSellOrder(this.symbol, this.positionSize);
// 模拟执行
const trade = {
timestamp: Date.now(),
side: 'sell',
amount: this.positionSize,
price: price,
cost: this.positionSize * price,
id: `sim_${Date.now()}`,
};
this.trades.push(trade);
this.position = -1; // 设置为空头
console.log(`✅ 卖出成功,持仓: ${this.position > 0 ? '多头' : '空头'}\n`);
} catch (error) {
console.error('❌ 卖出失败:', error.message);
}
}
// 计算简单移动平均线
calculateSMA(period) {
if (this.priceHistory.length < period) return [];
const sma = [];
for (let i = period - 1; i < this.priceHistory.length; i++) {
const sum = this.priceHistory
.slice(i - period + 1, i + 1)
.reduce((acc, item) => acc + item.close, 0);
sma.push(sum / period);
}
return sma;
}
// 显示当前状态
displayCurrentStatus(price, fastMA, slowMA) {
const positionText = this.position > 0 ? '多头 🟢' :
this.position < 0 ? '空头 🔴' : '空仓 ⚪';
console.log(`⏰ ${new Date().toLocaleTimeString()} | ${this.symbol}`);
console.log(`价格: $${price.toFixed(2)} | 快线: $${fastMA.toFixed(2)} | 慢线: $${slowMA.toFixed(2)} | 持仓: ${positionText}`);
}
// 计算策略表现
calculatePerformance() {
if (this.trades.length === 0) {
return { totalReturn: 0, winRate: 0, tradesCount: 0 };
}
let totalReturn = 0;
let wins = 0;
let entryPrice = null;
this.trades.forEach(trade => {
if (trade.side === 'buy') {
entryPrice = trade.price;
} else if (trade.side === 'sell' && entryPrice) {
const tradeReturn = (trade.price - entryPrice) / entryPrice;
totalReturn += tradeReturn;
if (tradeReturn > 0) wins++;
entryPrice = null;
}
});
const completedTrades = Math.floor(this.trades.length / 2);
const winRate = completedTrades > 0 ? (wins / completedTrades) * 100 : 0;
return {
totalReturn: totalReturn * 100,
winRate,
tradesCount: this.trades.length,
completedTrades,
};
}
// 获取时间周期毫秒数
getTimeframeMs() {
const timeframes = {
'1m': 60000,
'5m': 300000,
'15m': 900000,
'1h': 3600000,
'4h': 14400000,
'1d': 86400000,
};
return timeframes[this.timeframe] || 3600000;
}
// 显示策略报告
displayReport() {
const performance = this.calculatePerformance();
console.log('\n📊 策略表现报告:');
console.log('='.repeat(40));
console.log(`交易对: ${this.symbol}`);
console.log(`策略: MA(${this.fastPeriod}) × MA(${this.slowPeriod})`);
console.log(`总交易数: ${performance.tradesCount}`);
console.log(`完成交易: ${performance.completedTrades}`);
console.log(`胜率: ${performance.winRate.toFixed(1)}%`);
console.log(`总收益率: ${performance.totalReturn.toFixed(2)}%`);
console.log(`信号数: ${this.signals.length}`);
console.log('='.repeat(40));
}
// 停止策略
stop() {
this.isRunning = false;
this.displayReport();
console.log('⏹️ 策略已停止');
}
async sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// 使用示例
async function quantStrategyExample() {
const exchange = new ccxt.binance({ enableRateLimit: true });
await exchange.loadMarkets();
const strategy = new MovingAverageCrossStrategy(exchange, {
symbol: 'BTC/USDT',
fastPeriod: 5,
slowPeriod: 20,
timeframe: '1h',
positionSize: 0.001,
});
// 运行5分钟后停止
setTimeout(() => strategy.stop(), 300000);
await strategy.start();
}
// quantStrategyExample();
📊 投资组合管理
智能投资组合管理器
javascript
class PortfolioManager {
constructor(exchanges, config = {}) {
this.exchanges = Array.isArray(exchanges) ? exchanges : [exchanges];
this.baseCurrency = config.baseCurrency || 'USDT';
this.rebalanceThreshold = config.rebalanceThreshold || 5; // 5%
this.maxPositionSize = config.maxPositionSize || 30; // 30%
this.minPositionSize = config.minPositionSize || 1; // 1%
this.portfolio = {
totalValue: 0,
positions: new Map(),
cash: 0,
lastUpdate: null,
};
this.targetAllocation = new Map();
this.rebalanceHistory = [];
}
// 设置目标配置
setTargetAllocation(allocations) {
this.targetAllocation.clear();
let totalPercent = 0;
for (const [asset, percent] of Object.entries(allocations)) {
this.targetAllocation.set(asset, percent);
totalPercent += percent;
}
if (Math.abs(totalPercent - 100) > 0.1) {
throw new Error(`目标配置总和必须为100%,当前为${totalPercent}%`);
}
console.log('🎯 目标配置已设置:');
for (const [asset, percent] of this.targetAllocation) {
console.log(` ${asset}: ${percent}%`);
}
console.log('');
}
// 更新投资组合数据
async updatePortfolio() {
console.log('🔄 更新投资组合数据...');
const allBalances = new Map();
const allPrices = new Map();
// 获取所有交易所的余额
for (const exchange of this.exchanges) {
try {
const balance = await exchange.fetchBalance();
for (const [currency, amounts] of Object.entries(balance)) {
if (['info', 'free', 'used', 'total'].includes(currency)) continue;
if (amounts.total <= 0) continue;
const current = allBalances.get(currency) || 0;
allBalances.set(currency, current + amounts.total);
}
} catch (error) {
console.warn(`⚠️ 获取 ${exchange.id} 余额失败: ${error.message}`);
}
}
// 获取价格数据
await this.updatePrices(allBalances, allPrices);
// 计算投资组合价值
this.calculatePortfolioValue(allBalances, allPrices);
this.portfolio.lastUpdate = Date.now();
console.log('✅ 投资组合数据更新完成\n');
}
// 更新价格数据
async updatePrices(balances, prices) {
const exchange = this.exchanges[0]; // 使用第一个交易所获取价格
for (const currency of balances.keys()) {
if (currency === this.baseCurrency) {
prices.set(currency, 1);
continue;
}
const symbol = `${currency}/${this.baseCurrency}`;
try {
if (exchange.symbols.includes(symbol)) {
const ticker = await exchange.fetchTicker(symbol);
prices.set(currency, ticker.last);
} else {
console.warn(`⚠️ 无法获取 ${symbol} 价格`);
prices.set(currency, 0);
}
await this.sleep(200); // 避免频率限制
} catch (error) {
console.warn(`⚠️ 获取 ${symbol} 价格失败: ${error.message}`);
prices.set(currency, 0);
}
}
}
// 计算投资组合价值
calculatePortfolioValue(balances, prices) {
this.portfolio.positions.clear();
this.portfolio.totalValue = 0;
this.portfolio.cash = balances.get(this.baseCurrency) || 0;
for (const [currency, amount] of balances) {
const price = prices.get(currency) || 0;
const value = amount * price;
if (value > 0) {
this.portfolio.positions.set(currency, {
amount,
price,
value,
percentage: 0, // 稍后计算
});
this.portfolio.totalValue += value;
}
}
// 计算百分比
for (const [currency, position] of this.portfolio.positions) {
position.percentage = (position.value / this.portfolio.totalValue) * 100;
}
}
// 分析投资组合
analyzePortfolio() {
if (this.portfolio.positions.size === 0) {
console.log('📭 投资组合为空');
return null;
}
console.log('📊 投资组合分析:');
console.log('='.repeat(60));
console.log(`总价值: ${this.portfolio.totalValue.toFixed(2)} ${this.baseCurrency}`);
console.log(`现金: ${this.portfolio.cash.toFixed(2)} ${this.baseCurrency} (${(this.portfolio.cash/this.portfolio.totalValue*100).toFixed(1)}%)`);
console.log('');
// 按价值排序显示持仓
const sortedPositions = Array.from(this.portfolio.positions.entries())
.sort(([,a], [,b]) => b.value - a.value);
console.log('资产'.padEnd(8) + '数量'.padEnd(15) + '价格'.padEnd(12) + '价值'.padEnd(15) + '占比');
console.log('-'.repeat(60));
sortedPositions.forEach(([currency, position]) => {
console.log(
`${currency.padEnd(8)}` +
`${position.amount.toFixed(4).padEnd(15)}` +
`${position.price.toFixed(2).padEnd(12)}` +
`${position.value.toFixed(2).padEnd(15)}` +
`${position.percentage.toFixed(1)}%`
);
});
console.log('='.repeat(60));
// 与目标配置对比
if (this.targetAllocation.size > 0) {
this.compareWithTarget();
}
return this.portfolio;
}
// 与目标配置对比
compareWithTarget() {
console.log('\n🎯 目标配置对比:');
console.log('-'.repeat(50));
const deviations = [];
for (const [asset, targetPercent] of this.targetAllocation) {
const currentPosition = this.portfolio.positions.get(asset);
const currentPercent = currentPosition ? currentPosition.percentage : 0;
const deviation = currentPercent - targetPercent;
deviations.push({
asset,
target: targetPercent,
current: currentPercent,
deviation,
needsRebalance: Math.abs(deviation) > this.rebalanceThreshold,
});
const statusEmoji = Math.abs(deviation) > this.rebalanceThreshold ? '⚠️' : '✅';
console.log(
`${statusEmoji} ${asset.padEnd(8)}: ` +
`目标 ${targetPercent.toFixed(1)}% | ` +
`当前 ${currentPercent.toFixed(1)}% | ` +
`偏差 ${deviation > 0 ? '+' : ''}${deviation.toFixed(1)}%`
);
}
// 检查是否需要再平衡
const needsRebalance = deviations.some(d => d.needsRebalance);
if (needsRebalance) {
console.log('\n🔄 建议进行再平衡操作');
this.generateRebalanceActions(deviations);
} else {
console.log('\n✅ 投资组合配置符合目标');
}
}
// 生成再平衡操作建议
generateRebalanceActions(deviations) {
console.log('\n📋 再平衡操作建议:');
const actions = [];
deviations.forEach(deviation => {
if (!deviation.needsRebalance) return;
const targetValue = (this.portfolio.totalValue * deviation.target) / 100;
const currentValue = (this.portfolio.totalValue * deviation.current) / 100;
const valueChange = targetValue - currentValue;
if (Math.abs(valueChange) < 10) return; // 忽略小额调整
const action = {
asset: deviation.asset,
action: valueChange > 0 ? 'buy' : 'sell',
valueChange: Math.abs(valueChange),
targetPercent: deviation.target,
currentPercent: deviation.current,
};
actions.push(action);
const actionEmoji = action.action === 'buy' ? '🟢' : '🔴';
console.log(
`${actionEmoji} ${action.action.toUpperCase()} ${action.asset}: ` +
`${action.valueChange.toFixed(2)} ${this.baseCurrency} ` +
`(${action.currentPercent.toFixed(1)}% → ${action.targetPercent.toFixed(1)}%)`
);
});
return actions;
}
// 执行再平衡
async executeRebalance(dryRun = true) {
if (this.targetAllocation.size === 0) {
throw new Error('未设置目标配置');
}
await this.updatePortfolio();
const deviations = [];
for (const [asset, targetPercent] of this.targetAllocation) {
const currentPosition = this.portfolio.positions.get(asset);
const currentPercent = currentPosition ? currentPosition.percentage : 0;
const deviation = currentPercent - targetPercent;
if (Math.abs(deviation) > this.rebalanceThreshold) {
deviations.push({
asset,
target: targetPercent,
current: currentPercent,
deviation,
});
}
}
if (deviations.length === 0) {
console.log('✅ 无需再平衡');
return;
}
console.log(`🔄 ${dryRun ? '模拟' : '执行'}再平衡操作...`);
const actions = this.generateRebalanceActions(deviations);
if (!dryRun) {
// 这里应该实际执行交易
console.log('⚠️ 实际交易执行需要实现具体的下单逻辑');
}
// 记录再平衡历史
this.rebalanceHistory.push({
timestamp: Date.now(),
actions,
portfolioValue: this.portfolio.totalValue,
dryRun,
});
return actions;
}
// 风险分析
calculateRiskMetrics() {
if (this.portfolio.positions.size === 0) return null;
const positions = Array.from(this.portfolio.positions.values());
// 计算集中度风险
const concentrationRisk = Math.max(...positions.map(p => p.percentage));
// 计算多样化程度
const diversificationScore = 100 - concentrationRisk;
// 计算风险等级
let riskLevel = 'low';
if (concentrationRisk > 50) riskLevel = 'high';
else if (concentrationRisk > 30) riskLevel = 'medium';
const riskMetrics = {
concentrationRisk: concentrationRisk.toFixed(1),
diversificationScore: diversificationScore.toFixed(1),
riskLevel,
positionCount: this.portfolio.positions.size,
largestPosition: Math.max(...positions.map(p => p.percentage)),
};
console.log('\n⚠️ 风险分析:');
console.log(`集中度风险: ${riskMetrics.concentrationRisk}%`);
console.log(`多样化评分: ${riskMetrics.diversificationScore}%`);
console.log(`风险等级: ${riskLevel.toUpperCase()}`);
console.log(`持仓数量: ${riskMetrics.positionCount}`);
return riskMetrics;
}
// 生成投资组合报告
async generateReport() {
await this.updatePortfolio();
console.log('\n📈 投资组合完整报告');
console.log('='.repeat(80));
console.log(`生成时间: ${new Date().toLocaleString()}`);
console.log(`更新时间: ${new Date(this.portfolio.lastUpdate).toLocaleString()}`);
// 基本信息
this.analyzePortfolio();
// 风险分析
this.calculateRiskMetrics();
// 再平衡历史
if (this.rebalanceHistory.length > 0) {
console.log('\n📋 再平衡历史:');
this.rebalanceHistory.slice(-5).forEach((rebalance, index) => {
const time = new Date(rebalance.timestamp).toLocaleString();
console.log(`${index + 1}. ${time} - ${rebalance.actions.length} 个操作 (${rebalance.dryRun ? '模拟' : '实际'})`);
});
}
console.log('='.repeat(80));
}
async sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// 使用示例
async function portfolioExample() {
const exchange = new ccxt.binance({
apiKey: process.env.BINANCE_API_KEY,
secret: process.env.BINANCE_SECRET,
enableRateLimit: true,
sandbox: true,
});
await exchange.loadMarkets();
const portfolio = new PortfolioManager([exchange], {
baseCurrency: 'USDT',
rebalanceThreshold: 5,
});
// 设置目标配置
portfolio.setTargetAllocation({
'BTC': 40,
'ETH': 30,
'BNB': 20,
'USDT': 10,
});
// 生成报告
await portfolio.generateReport();
// 检查是否需要再平衡
await portfolio.executeRebalance(true); // 模拟运行
}
// portfolioExample();
🛡️ 风险管理系统
风险控制管理器
javascript
class RiskManager {
constructor(config = {}) {
this.maxDailyLoss = config.maxDailyLoss || 5; // 5%
this.maxPositionSize = config.maxPositionSize || 10; // 10%
this.maxLeverage = config.maxLeverage || 3; // 3倍
this.stopLossPercent = config.stopLossPercent || 2; // 2%
this.maxCorrelation = config.maxCorrelation || 0.8; // 80%
this.dailyPnL = 0;
this.startOfDayValue = 0;
this.positions = new Map();
this.riskEvents = [];
this.isEmergencyMode = false;
}
// 设置交易日开始值
setStartOfDayValue(value) {
this.startOfDayValue = value;
this.dailyPnL = 0;
console.log(`📅 交易日开始,初始价值: ${value.toFixed(2)}`);
}
// 更新当前组合价值
updatePortfolioValue(currentValue) {
if (this.startOfDayValue === 0) {
this.setStartOfDayValue(currentValue);
return;
}
this.dailyPnL = ((currentValue - this.startOfDayValue) / this.startOfDayValue) * 100;
// 检查每日损失限制
this.checkDailyLossLimit();
}
// 检查每日损失限制
checkDailyLossLimit() {
if (this.dailyPnL <= -this.maxDailyLoss) {
this.triggerEmergencyMode('daily_loss_limit', {
currentLoss: this.dailyPnL,
limit: this.maxDailyLoss,
});
}
}
// 检查订单风险
checkOrderRisk(order, portfolioValue) {
const risks = [];
// 检查仓位大小
const positionValue = order.amount * order.price;
const positionPercent = (positionValue / portfolioValue) * 100;
if (positionPercent > this.maxPositionSize) {
risks.push({
type: 'position_size',
severity: 'high',
message: `仓位过大: ${positionPercent.toFixed(1)}% > ${this.maxPositionSize}%`,
value: positionPercent,
limit: this.maxPositionSize,
});
}
// 检查杠杆
if (order.leverage && order.leverage > this.maxLeverage) {
risks.push({
type: 'leverage',
severity: 'high',
message: `杠杆过高: ${order.leverage}x > ${this.maxLeverage}x`,
value: order.leverage,
limit: this.maxLeverage,
});
}
// 检查止损设置
if (order.side === 'buy' && !order.stopLoss) {
risks.push({
type: 'no_stop_loss',
severity: 'medium',
message: '建议设置止损价格',
});
}
return risks;
}
// 验证订单
validateOrder(order, portfolioValue) {
if (this.isEmergencyMode) {
throw new Error('🚨 应急模式激活,暂停所有交易');
}
const risks = this.checkOrderRisk(order, portfolioValue);
const highRisks = risks.filter(risk => risk.severity === 'high');
if (highRisks.length > 0) {
console.error('🚫 订单风险过高:');
highRisks.forEach(risk => {
console.error(` - ${risk.message}`);
});
return false;
}
if (risks.length > 0) {
console.warn('⚠️ 订单风险警告:');
risks.forEach(risk => {
console.warn(` - ${risk.message}`);
});
}
return true;
}
// 计算建议止损价格
calculateStopLoss(entryPrice, side) {
const stopLossMultiplier = this.stopLossPercent / 100;
if (side === 'buy') {
return entryPrice * (1 - stopLossMultiplier);
} else {
return entryPrice * (1 + stopLossMultiplier);
}
}
// 添加持仓
addPosition(positionId, position) {
this.positions.set(positionId, {
...position,
entryTime: Date.now(),
stopLoss: position.stopLoss || this.calculateStopLoss(position.entryPrice, position.side),
maxDrawdown: 0,
unrealizedPnL: 0,
});
console.log(`📍 新建持仓: ${positionId}`);
this.displayPosition(positionId);
}
// 更新持仓
updatePosition(positionId, currentPrice) {
const position = this.positions.get(positionId);
if (!position) return;
// 计算未实现盈亏
const pnl = position.side === 'buy' ?
(currentPrice - position.entryPrice) / position.entryPrice :
(position.entryPrice - currentPrice) / position.entryPrice;
position.unrealizedPnL = pnl * 100;
position.currentPrice = currentPrice;
// 更新最大回撤
if (position.unrealizedPnL < position.maxDrawdown) {
position.maxDrawdown = position.unrealizedPnL;
}
// 检查止损
this.checkStopLoss(positionId);
// 检查持仓风险
this.checkPositionRisk(positionId);
}
// 检查止损
checkStopLoss(positionId) {
const position = this.positions.get(positionId);
if (!position || !position.stopLoss) return;
const shouldTriggerStopLoss = position.side === 'buy' ?
position.currentPrice <= position.stopLoss :
position.currentPrice >= position.stopLoss;
if (shouldTriggerStopLoss) {
this.triggerStopLoss(positionId);
}
}
// 检查持仓风险
checkPositionRisk(positionId) {
const position = this.positions.get(positionId);
if (!position) return;
// 检查是否达到风险阈值
if (position.unrealizedPnL <= -this.stopLossPercent) {
this.recordRiskEvent('position_loss_threshold', {
positionId,
unrealizedPnL: position.unrealizedPnL,
threshold: -this.stopLossPercent,
});
}
// 检查持仓时间
const holdingTime = Date.now() - position.entryTime;
const maxHoldingTime = 7 * 24 * 60 * 60 * 1000; // 7天
if (holdingTime > maxHoldingTime) {
this.recordRiskEvent('long_holding_time', {
positionId,
holdingDays: Math.floor(holdingTime / (24 * 60 * 60 * 1000)),
});
}
}
// 触发止损
triggerStopLoss(positionId) {
const position = this.positions.get(positionId);
if (!position) return;
console.log(`🛑 触发止损: ${positionId}`);
console.log(` 止损价: ${position.stopLoss.toFixed(2)}`);
console.log(` 当前价: ${position.currentPrice.toFixed(2)}`);
console.log(` 损失: ${position.unrealizedPnL.toFixed(2)}%`);
// 这里应该执行实际的止损订单
// await this.executeStopLoss(positionId);
this.recordRiskEvent('stop_loss_triggered', {
positionId,
stopLossPrice: position.stopLoss,
currentPrice: position.currentPrice,
loss: position.unrealizedPnL,
});
}
// 触发应急模式
triggerEmergencyMode(reason, data) {
if (this.isEmergencyMode) return;
this.isEmergencyMode = true;
console.error('🚨 触发应急模式!');
console.error(`原因: ${reason}`);
console.error('数据:', data);
this.recordRiskEvent('emergency_mode', {
reason,
data,
timestamp: Date.now(),
});
// 这里应该实施应急措施
// 如: 取消所有订单、平仓所有持仓等
this.executeEmergencyProcedures();
}
// 执行应急程序
executeEmergencyProcedures() {
console.log('🚨 执行应急程序:');
console.log(' 1. 取消所有挂单');
console.log(' 2. 平仓所有持仓');
console.log(' 3. 停止自动交易');
console.log(' 4. 发送告警通知');
// 实际实现中应该执行这些操作
}
// 记录风险事件
recordRiskEvent(type, data) {
const event = {
type,
data,
timestamp: Date.now(),
id: `${type}_${Date.now()}`,
};
this.riskEvents.push(event);
// 限制事件历史数量
if (this.riskEvents.length > 1000) {
this.riskEvents = this.riskEvents.slice(-1000);
}
console.warn(`⚠️ 风险事件: ${type}`, data);
}
// 显示持仓信息
displayPosition(positionId) {
const position = this.positions.get(positionId);
if (!position) return;
console.log(`📊 持仓 ${positionId}:`);
console.log(` 方向: ${position.side}`);
console.log(` 入场价: ${position.entryPrice.toFixed(2)}`);
console.log(` 数量: ${position.amount}`);
console.log(` 止损价: ${position.stopLoss?.toFixed(2) || 'N/A'}`);
console.log(` 未实现盈亏: ${position.unrealizedPnL?.toFixed(2) || 0}%`);
console.log('');
}
// 风险报告
generateRiskReport() {
console.log('\n🛡️ 风险管理报告');
console.log('='.repeat(50));
// 基本风险指标
console.log(`每日盈亏: ${this.dailyPnL.toFixed(2)}%`);
console.log(`每日损失限制: ${this.maxDailyLoss}%`);
console.log(`应急模式: ${this.isEmergencyMode ? '🔴 激活' : '🟢 正常'}`);
console.log(`活跃持仓: ${this.positions.size} 个`);
// 持仓概览
if (this.positions.size > 0) {
console.log('\n📊 持仓概览:');
for (const [id, position] of this.positions) {
const status = position.unrealizedPnL >= 0 ? '🟢' : '🔴';
console.log(` ${status} ${id}: ${position.unrealizedPnL?.toFixed(2) || 0}%`);
}
}
// 风险事件
const recentEvents = this.riskEvents.slice(-10);
if (recentEvents.length > 0) {
console.log('\n⚠️ 最近风险事件:');
recentEvents.forEach(event => {
const time = new Date(event.timestamp).toLocaleTimeString();
console.log(` ${time}: ${event.type}`);
});
}
console.log('='.repeat(50));
}
// 重置应急模式
resetEmergencyMode() {
if (!this.isEmergencyMode) return;
console.log('🔄 重置应急模式');
this.isEmergencyMode = false;
this.recordRiskEvent('emergency_mode_reset', {
timestamp: Date.now(),
});
}
// 获取风险指标
getRiskMetrics() {
const activePositions = Array.from(this.positions.values());
return {
dailyPnL: this.dailyPnL,
maxDailyLoss: this.maxDailyLoss,
isEmergencyMode: this.isEmergencyMode,
activePositions: this.positions.size,
averageUnrealizedPnL: activePositions.length > 0 ?
activePositions.reduce((sum, pos) => sum + (pos.unrealizedPnL || 0), 0) / activePositions.length : 0,
worstPosition: Math.min(...activePositions.map(pos => pos.unrealizedPnL || 0)),
riskEventsToday: this.riskEvents.filter(event =>
Date.now() - event.timestamp < 24 * 60 * 60 * 1000
).length,
};
}
}
// 使用示例
function riskManagementExample() {
const riskManager = new RiskManager({
maxDailyLoss: 3, // 3%
maxPositionSize: 15, // 15%
stopLossPercent: 2, // 2%
});
// 设置交易日开始价值
riskManager.setStartOfDayValue(10000);
// 模拟订单风险检查
const order = {
symbol: 'BTC/USDT',
side: 'buy',
amount: 0.1,
price: 45000,
leverage: 2,
};
const portfolioValue = 10000;
const isValid = riskManager.validateOrder(order, portfolioValue);
console.log(`订单验证结果: ${isValid ? '通过' : '拒绝'}`);
// 添加持仓
if (isValid) {
riskManager.addPosition('BTC_001', {
symbol: 'BTC/USDT',
side: 'buy',
amount: 0.1,
entryPrice: 45000,
});
// 模拟价格变化
riskManager.updatePosition('BTC_001', 44000); // 价格下跌
riskManager.updatePosition('BTC_001', 43000); // 继续下跌
}
// 模拟每日损失
riskManager.updatePortfolioValue(9500); // 组合价值下跌5%
// 生成风险报告
riskManager.generateRiskReport();
}
// riskManagementExample();
🎯 章节总结
本章我们学习了 CCXT 的高级应用场景:
✅ 多交易所套利
- 套利机会检测和分析
- 跨交易所价差监控
- 套利统计和评估
✅ 量化交易策略
- 移动平均线交叉策略
- 技术指标计算和信号生成
- 策略回测和性能评估
✅ 投资组合管理
- 多资产投资组合分析
- 目标配置和再平衡
- 风险分散和多样化评估
✅ 风险管理系统
- 多层次风险控制
- 实时风险监控和预警
- 应急处理和止损机制
💡 实践建议
- 从简单开始 - 先掌握基础功能再构建复杂策略
- 充分测试 - 在沙盒环境中验证所有策略
- 风险第一 - 建立完善的风险控制体系
- 持续优化 - 根据市场变化调整策略参数
- 记录分析 - 详细记录交易过程和结果
🔗 下一步
完成高级功能学习后,可以:
- 查阅常见问题 - 解决开发中的常见问题
- 实际项目开发 - 将所学知识应用到真实项目
- 社区交流 - 参与 CCXT 社区讨论和分享
下一章:常见问题与解决方案