第四章:账户与订单管理
本章将深入介绍如何使用 CCXT 进行账户管理和交易操作。⚠️ 重要提醒:本章涉及真实资金操作,请务必在沙盒环境中充分测试后再在生产环境使用!
🔐 API认证配置
安全的API密钥管理
javascript
// 推荐的安全配置方式
require('dotenv').config();
const ccxt = require('ccxt');
// 使用环境变量存储敏感信息
const exchange = new ccxt.binance({
apiKey: process.env.BINANCE_API_KEY,
secret: process.env.BINANCE_SECRET,
enableRateLimit: true,
sandbox: process.env.NODE_ENV !== 'production', // 开发环境使用沙盒
// 其他安全配置
adjustForTimeDifference: true,
recvWindow: 5000,
options: {
defaultType: 'spot', // 默认现货交易
}
});
// API权限验证
async function verifyApiCredentials() {
try {
console.log('🔑 验证API权限...');
// 测试API连接
const serverTime = await exchange.fetchTime();
const localTime = Date.now();
const timeDiff = Math.abs(serverTime - localTime);
console.log(`⏰ 服务器时间同步: ${timeDiff}ms`);
if (timeDiff > 10000) {
console.warn('⚠️ 时间差过大,可能影响API调用');
}
// 测试账户权限
const balance = await exchange.fetchBalance();
console.log('✅ API权限验证成功');
console.log(`💰 账户资产种类: ${Object.keys(balance).length - 3} 种`); // 排除info、free、used、total
return true;
} catch (error) {
console.error('❌ API权限验证失败:', error.message);
if (error.message.includes('API-key')) {
console.error('🔑 请检查API密钥是否正确');
} else if (error.message.includes('signature')) {
console.error('🔏 请检查API密钥签名是否正确');
} else if (error.message.includes('timestamp')) {
console.error('⏰ 请检查系统时间是否准确');
}
return false;
}
}
// verifyApiCredentials();
Python API认证示例
python
import os
import ccxt
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
# 安全的交易所配置
exchange = ccxt.binance({
'apiKey': os.getenv('BINANCE_API_KEY'),
'secret': os.getenv('BINANCE_SECRET'),
'enableRateLimit': True,
'sandbox': os.getenv('NODE_ENV') != 'production',
'options': {
'defaultType': 'spot',
}
})
async def verify_api_credentials():
"""验证API凭证"""
try:
print('🔑 验证API权限...')
# 测试API连接
balance = await exchange.fetch_balance()
print('✅ API权限验证成功')
# 显示账户信息
currencies = [k for k in balance.keys() if k not in ['info', 'free', 'used', 'total']]
print(f'💰 账户资产种类: {len(currencies)} 种')
return True
except Exception as error:
print(f'❌ API权限验证失败: {error}')
return False
💰 账户余额管理
详细余额查询
javascript
class BalanceManager {
constructor(exchange) {
this.exchange = exchange;
}
async getDetailedBalance() {
try {
console.log('💰 获取账户余额详情...\n');
const balance = await this.exchange.fetchBalance();
// 分析余额结构
const analysis = this.analyzeBalance(balance);
// 显示总资产概览
this.displayBalanceOverview(analysis);
// 显示具体持仓
this.displayHoldings(analysis.holdings);
// 显示冻结资产
if (analysis.frozenAssets.length > 0) {
this.displayFrozenAssets(analysis.frozenAssets);
}
return analysis;
} catch (error) {
console.error('❌ 获取余额失败:', error.message);
throw error;
}
}
analyzeBalance(balance) {
const holdings = [];
const frozenAssets = [];
let totalFreeValue = 0;
let totalUsedValue = 0;
// 遍历所有货币
Object.keys(balance).forEach(currency => {
if (['info', 'free', 'used', 'total'].includes(currency)) return;
const currencyBalance = balance[currency];
if (currencyBalance.total > 0) {
holdings.push({
currency: currency,
free: currencyBalance.free || 0,
used: currencyBalance.used || 0,
total: currencyBalance.total || 0,
});
// 累计价值(简化处理,实际应该换算成统一货币)
totalFreeValue += currencyBalance.free || 0;
totalUsedValue += currencyBalance.used || 0;
}
if (currencyBalance.used > 0) {
frozenAssets.push({
currency: currency,
amount: currencyBalance.used,
});
}
});
// 按总量排序
holdings.sort((a, b) => b.total - a.total);
return {
holdings,
frozenAssets,
totalHoldings: holdings.length,
totalFreeValue,
totalUsedValue,
balanceInfo: balance.info,
};
}
displayBalanceOverview(analysis) {
console.log('📊 账户资产概览:');
console.log(`持有币种: ${analysis.totalHoldings} 种`);
console.log(`可用资产数: ${analysis.totalFreeValue.toFixed(8)}`);
console.log(`冻结资产数: ${analysis.totalUsedValue.toFixed(8)}`);
console.log(`冻结资产种类: ${analysis.frozenAssets.length} 种\n`);
}
displayHoldings(holdings) {
if (holdings.length === 0) {
console.log('💸 暂无持仓');
return;
}
console.log('💎 持仓详情:');
console.log('-'.repeat(60));
console.log('币种 | 可用余额 | 冻结余额 | 总余额 ');
console.log('-'.repeat(60));
holdings.forEach(holding => {
const currency = holding.currency.padEnd(8);
const free = holding.free.toFixed(8).padStart(12);
const used = holding.used.toFixed(8).padStart(12);
const total = holding.total.toFixed(8).padStart(12);
console.log(`${currency} | ${free} | ${used} | ${total}`);
});
console.log('-'.repeat(60) + '\n');
}
displayFrozenAssets(frozenAssets) {
console.log('🔒 冻结资产:');
frozenAssets.forEach(asset => {
console.log(`${asset.currency}: ${asset.amount.toFixed(8)}`);
});
console.log('');
}
// 获取特定货币余额
async getCurrencyBalance(currency) {
const balance = await this.exchange.fetchBalance();
if (currency in balance) {
return {
currency: currency,
free: balance[currency].free || 0,
used: balance[currency].used || 0,
total: balance[currency].total || 0,
};
}
return {
currency: currency,
free: 0,
used: 0,
total: 0,
};
}
// 计算投资组合价值(需要价格数据)
async calculatePortfolioValue(baseCurrency = 'USDT') {
try {
const balance = await this.exchange.fetchBalance();
const analysis = this.analyzeBalance(balance);
let totalValue = 0;
const breakdown = [];
console.log(`💰 计算投资组合价值 (基准: ${baseCurrency})...\n`);
for (const holding of analysis.holdings) {
const { currency, total } = holding;
let value = 0;
let price = 0;
if (currency === baseCurrency) {
value = total;
price = 1;
} else {
// 尝试获取价格
const symbol = `${currency}/${baseCurrency}`;
try {
if (this.exchange.symbols.includes(symbol)) {
const ticker = await this.exchange.fetchTicker(symbol);
price = ticker.last;
value = total * price;
} else {
console.warn(`⚠️ 无法获取 ${symbol} 价格`);
continue;
}
} catch (error) {
console.warn(`⚠️ 获取 ${symbol} 价格失败: ${error.message}`);
continue;
}
}
totalValue += value;
breakdown.push({
currency,
amount: total,
price,
value,
percentage: 0, // 稍后计算
});
await this.exchange.sleep(200); // 避免频率限制
}
// 计算百分比
breakdown.forEach(item => {
item.percentage = (item.value / totalValue) * 100;
});
// 按价值排序
breakdown.sort((a, b) => b.value - a.value);
// 显示结果
console.log('📈 投资组合价值分析:');
console.log(`总价值: ${totalValue.toFixed(2)} ${baseCurrency}\n`);
console.log('📊 资产分布:');
breakdown.forEach(item => {
console.log(
`${item.currency.padEnd(8)}: ` +
`${item.amount.toFixed(4).padStart(12)} × ` +
`${item.price.toFixed(4).padStart(10)} = ` +
`${item.value.toFixed(2).padStart(12)} ${baseCurrency} ` +
`(${item.percentage.toFixed(2)}%)`
);
});
return {
totalValue,
baseCurrency,
breakdown,
};
} catch (error) {
console.error('❌ 计算投资组合价值失败:', error.message);
throw error;
}
}
}
// 使用示例
async function manageBalance() {
const exchange = new ccxt.binance({
apiKey: process.env.BINANCE_API_KEY,
secret: process.env.BINANCE_SECRET,
enableRateLimit: true,
sandbox: true, // 沙盒模式
});
await exchange.loadMarkets();
const balanceManager = new BalanceManager(exchange);
// 获取详细余额
await balanceManager.getDetailedBalance();
// 计算投资组合价值
await balanceManager.calculatePortfolioValue('USDT');
// 获取特定货币余额
const btcBalance = await balanceManager.getCurrencyBalance('BTC');
console.log('₿ BTC余额:', btcBalance);
}
// manageBalance();
📈 订单操作详解
市价订单
javascript
class OrderManager {
constructor(exchange) {
this.exchange = exchange;
}
// 市价买入订单
async createMarketBuyOrder(symbol, amount, options = {}) {
try {
console.log(`🟢 创建市价买入订单: ${symbol}`);
console.log(`数量: ${amount}`);
// 获取当前价格用于预估
const ticker = await this.exchange.fetchTicker(symbol);
const estimatedCost = amount * ticker.ask;
console.log(`预估成本: ${estimatedCost.toFixed(2)} ${symbol.split('/')[1]}`);
// 确认订单信息
const confirmation = await this.confirmOrder('市价买入', symbol, amount, ticker.ask, estimatedCost);
if (!confirmation) {
console.log('❌ 订单已取消');
return null;
}
// 创建订单
const order = await this.exchange.createMarketBuyOrder(symbol, amount, undefined, undefined, options);
console.log('✅ 市价买入订单创建成功!');
this.displayOrderInfo(order);
return order;
} catch (error) {
console.error('❌ 创建市价买入订单失败:', error.message);
throw error;
}
}
// 市价卖出订单
async createMarketSellOrder(symbol, amount, options = {}) {
try {
console.log(`🔴 创建市价卖出订单: ${symbol}`);
console.log(`数量: ${amount}`);
const ticker = await this.exchange.fetchTicker(symbol);
const estimatedValue = amount * ticker.bid;
console.log(`预估收入: ${estimatedValue.toFixed(2)} ${symbol.split('/')[1]}`);
const confirmation = await this.confirmOrder('市价卖出', symbol, amount, ticker.bid, estimatedValue);
if (!confirmation) {
console.log('❌ 订单已取消');
return null;
}
const order = await this.exchange.createMarketSellOrder(symbol, amount, undefined, undefined, options);
console.log('✅ 市价卖出订单创建成功!');
this.displayOrderInfo(order);
return order;
} catch (error) {
console.error('❌ 创建市价卖出订单失败:', error.message);
throw error;
}
}
// 按金额买入(常用于定投)
async buyWithQuoteAmount(symbol, quoteAmount, options = {}) {
try {
console.log(`💰 按金额买入: ${symbol}`);
console.log(`金额: ${quoteAmount} ${symbol.split('/')[1]}`);
// 某些交易所支持按金额买入
if (this.exchange.id === 'binance') {
options.quoteOrderQty = quoteAmount;
const order = await this.exchange.createMarketBuyOrder(
symbol,
0, // amount设为0,使用quoteOrderQty
undefined,
undefined,
options
);
console.log('✅ 按金额买入订单创建成功!');
this.displayOrderInfo(order);
return order;
} else {
// 手动计算数量
const ticker = await this.exchange.fetchTicker(symbol);
const amount = quoteAmount / ticker.ask;
return await this.createMarketBuyOrder(symbol, amount, options);
}
} catch (error) {
console.error('❌ 按金额买入失败:', error.message);
throw error;
}
}
// 限价订单
async createLimitOrder(symbol, side, amount, price, options = {}) {
try {
console.log(`📋 创建限价${side === 'buy' ? '买入' : '卖出'}订单: ${symbol}`);
console.log(`数量: ${amount}`);
console.log(`价格: ${price}`);
const cost = amount * price;
console.log(`总价值: ${cost.toFixed(2)} ${symbol.split('/')[1]}`);
// 获取当前价格进行比较
const ticker = await this.exchange.fetchTicker(symbol);
const currentPrice = ticker.last;
const priceDeviation = ((price - currentPrice) / currentPrice * 100).toFixed(2);
console.log(`当前价格: ${currentPrice}`);
console.log(`价格偏离: ${priceDeviation}%`);
const confirmation = await this.confirmOrder(
`限价${side === 'buy' ? '买入' : '卖出'}`,
symbol,
amount,
price,
cost
);
if (!confirmation) {
console.log('❌ 订单已取消');
return null;
}
const order = await this.exchange.createLimitOrder(symbol, side, amount, price, undefined, undefined, options);
console.log(`✅ 限价${side === 'buy' ? '买入' : '卖出'}订单创建成功!`);
this.displayOrderInfo(order);
return order;
} catch (error) {
console.error(`❌ 创建限价订单失败: ${error.message}`);
throw error;
}
}
// 止损订单(以Binance为例)
async createStopLossOrder(symbol, side, amount, stopPrice, limitPrice = null, options = {}) {
try {
if (this.exchange.id !== 'binance') {
throw new Error('此示例仅支持Binance交易所');
}
console.log(`🛑 创建止损订单: ${symbol}`);
console.log(`方向: ${side === 'buy' ? '买入' : '卖出'}`);
console.log(`数量: ${amount}`);
console.log(`止损价: ${stopPrice}`);
let orderType, orderOptions;
if (limitPrice) {
// 止损限价单
orderType = side === 'buy' ? 'STOP_LOSS_LIMIT' : 'STOP_LOSS_LIMIT';
orderOptions = {
...options,
stopPrice: stopPrice,
timeInForce: 'GTC',
};
console.log(`限价: ${limitPrice}`);
} else {
// 止损市价单
orderType = 'STOP_LOSS';
orderOptions = {
...options,
stopPrice: stopPrice,
};
}
const order = await this.exchange.createOrder(
symbol,
orderType,
side,
amount,
limitPrice || stopPrice,
undefined,
orderOptions
);
console.log('✅ 止损订单创建成功!');
this.displayOrderInfo(order);
return order;
} catch (error) {
console.error('❌ 创建止损订单失败:', error.message);
throw error;
}
}
// 订单确认(简化版,实际应用中可以更完善)
async confirmOrder(type, symbol, amount, price, totalValue) {
console.log('\n📋 订单确认:');
console.log(`类型: ${type}`);
console.log(`交易对: ${symbol}`);
console.log(`数量: ${amount}`);
console.log(`价格: ${price}`);
console.log(`总价值: ${totalValue.toFixed(4)}`);
console.log('\n确认提交订单? (在实际应用中这里应该有用户确认机制)');
// 在实际应用中,这里应该有用户确认机制
// 这里简化为直接返回true
return true;
}
// 显示订单信息
displayOrderInfo(order) {
console.log('\n📄 订单详情:');
console.log(`订单ID: ${order.id}`);
console.log(`交易对: ${order.symbol}`);
console.log(`方向: ${order.side === 'buy' ? '买入' : '卖出'}`);
console.log(`类型: ${order.type}`);
console.log(`状态: ${order.status}`);
console.log(`数量: ${order.amount}`);
console.log(`价格: ${order.price || '市价'}`);
console.log(`已成交数量: ${order.filled || 0}`);
console.log(`剩余数量: ${order.remaining || 0}`);
console.log(`成交金额: ${order.cost || 0}`);
console.log(`手续费: ${order.fee?.cost || 0} ${order.fee?.currency || ''}`);
console.log(`创建时间: ${new Date(order.timestamp).toLocaleString()}`);
console.log('');
}
// 订单精度处理
adjustOrderPrecision(symbol, amount, price) {
// 获取市场精度要求
const market = this.exchange.markets[symbol];
if (market) {
// 调整数量精度
const preciseAmount = this.exchange.amountToPrecision(symbol, amount);
// 调整价格精度
const precisePrice = price ? this.exchange.priceToPrecision(symbol, price) : undefined;
return {
amount: parseFloat(preciseAmount),
price: precisePrice ? parseFloat(precisePrice) : undefined,
};
}
return { amount, price };
}
}
// 使用示例
async function tradingExample() {
const exchange = new ccxt.binance({
apiKey: process.env.BINANCE_API_KEY,
secret: process.env.BINANCE_SECRET,
enableRateLimit: true,
sandbox: true, // 沙盒模式
});
await exchange.loadMarkets();
const orderManager = new OrderManager(exchange);
try {
// 示例1: 市价买入
// const marketBuyOrder = await orderManager.createMarketBuyOrder('BTC/USDT', 0.001);
// 示例2: 限价卖出
// const limitSellOrder = await orderManager.createLimitOrder('BTC/USDT', 'sell', 0.001, 50000);
// 示例3: 按金额买入(适合定投)
// const buyOrder = await orderManager.buyWithQuoteAmount('BTC/USDT', 100); // 用100 USDT买入BTC
// 示例4: 止损订单
// const stopLossOrder = await orderManager.createStopLossOrder('BTC/USDT', 'sell', 0.001, 45000, 44000);
console.log('📊 交易示例已准备就绪(已注释,取消注释以执行)');
} catch (error) {
console.error('❌ 交易示例执行失败:', error.message);
}
}
// tradingExample();
📋 订单查询与管理
订单状态查询
javascript
class OrderQueryManager {
constructor(exchange) {
this.exchange = exchange;
}
// 查询单个订单
async fetchOrder(orderId, symbol) {
try {
console.log(`🔍 查询订单: ${orderId}`);
const order = await this.exchange.fetchOrder(orderId, symbol);
this.displayDetailedOrderInfo(order);
return order;
} catch (error) {
console.error('❌ 查询订单失败:', error.message);
throw error;
}
}
// 查询未完成订单
async fetchOpenOrders(symbol = undefined) {
try {
console.log(`📋 查询未完成订单${symbol ? ` (${symbol})` : ''}...`);
const orders = await this.exchange.fetchOpenOrders(symbol);
if (orders.length === 0) {
console.log('✅ 暂无未完成订单');
return [];
}
console.log(`📊 找到 ${orders.length} 个未完成订单:\n`);
// 按时间排序
orders.sort((a, b) => a.timestamp - b.timestamp);
// 显示订单列表
this.displayOrderList(orders);
return orders;
} catch (error) {
console.error('❌ 查询未完成订单失败:', error.message);
throw error;
}
}
// 查询订单历史
async fetchOrderHistory(symbol = undefined, limit = 50) {
try {
console.log(`📚 查询订单历史${symbol ? ` (${symbol})` : ''}...`);
let orders = [];
// 尝试不同的方法获取历史订单
if (this.exchange.has['fetchOrders']) {
orders = await this.exchange.fetchOrders(symbol, undefined, limit);
} else if (this.exchange.has['fetchClosedOrders']) {
orders = await this.exchange.fetchClosedOrders(symbol, undefined, limit);
} else {
throw new Error('该交易所不支持查询订单历史');
}
if (orders.length === 0) {
console.log('📭 暂无历史订单');
return [];
}
// 按时间倒序排序(最新的在前)
orders.sort((a, b) => b.timestamp - a.timestamp);
console.log(`📊 找到 ${orders.length} 个历史订单:\n`);
// 分析订单统计
const stats = this.analyzeOrderStats(orders);
this.displayOrderStats(stats);
// 显示订单列表
this.displayOrderList(orders.slice(0, 20)); // 只显示前20个
return orders;
} catch (error) {
console.error('❌ 查询订单历史失败:', error.message);
throw error;
}
}
// 订单状态监控
async monitorOrder(orderId, symbol, maxWaitTime = 300000) { // 5分钟超时
console.log(`👀 开始监控订单: ${orderId}`);
console.log(`最大等待时间: ${maxWaitTime / 1000} 秒\n`);
const startTime = Date.now();
let lastStatus = null;
while (Date.now() - startTime < maxWaitTime) {
try {
const order = await this.exchange.fetchOrder(orderId, symbol);
if (order.status !== lastStatus) {
console.log(`⏰ ${new Date().toLocaleTimeString()} - 订单状态: ${order.status}`);
if (order.status === 'closed') {
console.log('✅ 订单已完全成交!');
this.displayDetailedOrderInfo(order);
return order;
} else if (order.status === 'canceled') {
console.log('❌ 订单已取消');
this.displayDetailedOrderInfo(order);
return order;
} else if (order.status === 'partially_filled') {
console.log(`📊 部分成交: ${order.filled}/${order.amount}`);
}
lastStatus = order.status;
}
// 等待一段时间后再次检查
await new Promise(resolve => setTimeout(resolve, 5000));
} catch (error) {
console.error('❌ 监控订单时出错:', error.message);
await new Promise(resolve => setTimeout(resolve, 10000));
}
}
console.log('⏰ 监控超时');
return null;
}
// 取消订单
async cancelOrder(orderId, symbol) {
try {
console.log(`🗑️ 取消订单: ${orderId}`);
const result = await this.exchange.cancelOrder(orderId, symbol);
console.log('✅ 订单取消成功');
this.displayDetailedOrderInfo(result);
return result;
} catch (error) {
console.error('❌ 取消订单失败:', error.message);
throw error;
}
}
// 批量取消订单
async cancelAllOrders(symbol = undefined) {
try {
console.log(`🗑️ 批量取消订单${symbol ? ` (${symbol})` : ''}...`);
if (this.exchange.has['cancelAllOrders']) {
const result = await this.exchange.cancelAllOrders(symbol);
console.log(`✅ 成功取消 ${result.length || 0} 个订单`);
return result;
} else {
// 手动批量取消
const openOrders = await this.exchange.fetchOpenOrders(symbol);
if (openOrders.length === 0) {
console.log('✅ 没有需要取消的订单');
return [];
}
console.log(`📋 找到 ${openOrders.length} 个未完成订单,开始逐个取消...`);
const results = [];
for (const order of openOrders) {
try {
const result = await this.exchange.cancelOrder(order.id, order.symbol);
results.push(result);
console.log(`✅ 取消订单: ${order.id}`);
// 避免频率限制
await this.exchange.sleep(500);
} catch (error) {
console.error(`❌ 取消订单 ${order.id} 失败: ${error.message}`);
}
}
console.log(`✅ 批量取消完成,成功取消 ${results.length}/${openOrders.length} 个订单`);
return results;
}
} catch (error) {
console.error('❌ 批量取消订单失败:', error.message);
throw error;
}
}
// 显示详细订单信息
displayDetailedOrderInfo(order) {
console.log('\n' + '='.repeat(60));
console.log('📄 订单详细信息');
console.log('='.repeat(60));
console.log(`订单ID: ${order.id}`);
console.log(`客户端ID: ${order.clientOrderId || 'N/A'}`);
console.log(`交易对: ${order.symbol}`);
console.log(`方向: ${order.side === 'buy' ? '买入 🟢' : '卖出 🔴'}`);
console.log(`类型: ${order.type}`);
console.log(`状态: ${this.getStatusEmoji(order.status)} ${order.status}`);
console.log(`数量: ${order.amount}`);
console.log(`价格: ${order.price || '市价'}`);
console.log(`已成交: ${order.filled || 0} (${((order.filled || 0) / order.amount * 100).toFixed(2)}%)`);
console.log(`剩余: ${order.remaining || 0}`);
console.log(`成交金额: ${order.cost || 0}`);
console.log(`平均成交价: ${order.average || 'N/A'}`);
if (order.fee) {
console.log(`手续费: ${order.fee.cost} ${order.fee.currency}`);
}
console.log(`创建时间: ${new Date(order.timestamp).toLocaleString()}`);
if (order.lastTradeTimestamp) {
console.log(`最后成交: ${new Date(order.lastTradeTimestamp).toLocaleString()}`);
}
console.log('='.repeat(60) + '\n');
}
// 显示订单列表
displayOrderList(orders) {
if (orders.length === 0) return;
console.log('订单ID'.padEnd(20) + '交易对'.padEnd(12) + '方向'.padEnd(6) + '类型'.padEnd(8) +
'状态'.padEnd(8) + '数量'.padEnd(12) + '价格'.padEnd(12) + '创建时间');
console.log('-'.repeat(100));
orders.forEach(order => {
const id = order.id.substring(0, 18).padEnd(20);
const symbol = order.symbol.padEnd(12);
const side = (order.side === 'buy' ? '买入' : '卖出').padEnd(6);
const type = order.type.padEnd(8);
const status = order.status.padEnd(8);
const amount = order.amount.toFixed(4).padEnd(12);
const price = (order.price || 'market').toString().substring(0, 10).padEnd(12);
const time = new Date(order.timestamp).toLocaleDateString();
console.log(`${id}${symbol}${side}${type}${status}${amount}${price}${time}`);
});
console.log('');
}
// 分析订单统计
analyzeOrderStats(orders) {
const stats = {
total: orders.length,
closed: 0,
canceled: 0,
open: 0,
partiallyFilled: 0,
buyOrders: 0,
sellOrders: 0,
marketOrders: 0,
limitOrders: 0,
totalVolume: 0,
totalValue: 0,
};
orders.forEach(order => {
// 状态统计
switch (order.status) {
case 'closed': stats.closed++; break;
case 'canceled': stats.canceled++; break;
case 'open': stats.open++; break;
case 'partially_filled': stats.partiallyFilled++; break;
}
// 方向统计
if (order.side === 'buy') stats.buyOrders++;
else stats.sellOrders++;
// 类型统计
if (order.type === 'market') stats.marketOrders++;
else if (order.type === 'limit') stats.limitOrders++;
// 成交量统计
if (order.filled) {
stats.totalVolume += order.filled;
if (order.cost) {
stats.totalValue += order.cost;
}
}
});
return stats;
}
// 显示订单统计
displayOrderStats(stats) {
console.log('📊 订单统计:');
console.log(`总订单数: ${stats.total}`);
console.log(`已完成: ${stats.closed} | 已取消: ${stats.canceled} | 进行中: ${stats.open} | 部分成交: ${stats.partiallyFilled}`);
console.log(`买入订单: ${stats.buyOrders} | 卖出订单: ${stats.sellOrders}`);
console.log(`市价订单: ${stats.marketOrders} | 限价订单: ${stats.limitOrders}`);
console.log(`总成交量: ${stats.totalVolume.toFixed(4)}`);
console.log(`总成交额: ${stats.totalValue.toFixed(2)}\n`);
}
// 获取状态表情符号
getStatusEmoji(status) {
const emojis = {
'open': '🟡',
'closed': '✅',
'canceled': '❌',
'partially_filled': '🟠',
'pending': '⏳',
'expired': '⏰',
};
return emojis[status] || '❓';
}
}
// 使用示例
async function orderManagementExample() {
const exchange = new ccxt.binance({
apiKey: process.env.BINANCE_API_KEY,
secret: process.env.BINANCE_SECRET,
enableRateLimit: true,
sandbox: true,
});
const queryManager = new OrderQueryManager(exchange);
try {
// 查询未完成订单
await queryManager.fetchOpenOrders();
// 查询订单历史
await queryManager.fetchOrderHistory('BTC/USDT', 20);
// 监控订单(需要有效的订单ID)
// await queryManager.monitorOrder('order-id', 'BTC/USDT');
} catch (error) {
console.error('❌ 订单管理示例失败:', error.message);
}
}
// orderManagementExample();
📊 交易历史分析
成交记录查询
javascript
class TradeHistoryAnalyzer {
constructor(exchange) {
this.exchange = exchange;
}
// 获取交易历史
async fetchMyTrades(symbol = undefined, limit = 100) {
try {
console.log(`📈 获取交易历史${symbol ? ` (${symbol})` : ''}...`);
if (!this.exchange.has['fetchMyTrades']) {
throw new Error('该交易所不支持查询交易历史');
}
const trades = await this.exchange.fetchMyTrades(symbol, undefined, limit);
if (trades.length === 0) {
console.log('📭 暂无交易记录');
return [];
}
console.log(`📊 获取到 ${trades.length} 条交易记录\n`);
// 分析交易数据
const analysis = this.analyzeTrades(trades);
// 显示分析结果
this.displayTradeAnalysis(analysis);
return trades;
} catch (error) {
console.error('❌ 获取交易历史失败:', error.message);
throw error;
}
}
// 分析交易数据
analyzeTrades(trades) {
const analysis = {
totalTrades: trades.length,
buyTrades: 0,
sellTrades: 0,
totalVolume: 0,
totalValue: 0,
totalFees: 0,
avgPrice: 0,
vwap: 0,
symbolStats: {},
timeRange: {
start: null,
end: null,
},
profitLoss: 0,
};
let totalPriceVolume = 0;
trades.forEach(trade => {
// 基础统计
if (trade.side === 'buy') {
analysis.buyTrades++;
} else {
analysis.sellTrades++;
}
analysis.totalVolume += trade.amount;
analysis.totalValue += trade.cost;
totalPriceVolume += trade.price * trade.amount;
if (trade.fee && trade.fee.cost) {
analysis.totalFees += trade.fee.cost;
}
// 按交易对统计
if (!analysis.symbolStats[trade.symbol]) {
analysis.symbolStats[trade.symbol] = {
trades: 0,
volume: 0,
value: 0,
buyTrades: 0,
sellTrades: 0,
};
}
const symbolStat = analysis.symbolStats[trade.symbol];
symbolStat.trades++;
symbolStat.volume += trade.amount;
symbolStat.value += trade.cost;
if (trade.side === 'buy') {
symbolStat.buyTrades++;
} else {
symbolStat.sellTrades++;
}
// 时间范围
if (!analysis.timeRange.start || trade.timestamp < analysis.timeRange.start) {
analysis.timeRange.start = trade.timestamp;
}
if (!analysis.timeRange.end || trade.timestamp > analysis.timeRange.end) {
analysis.timeRange.end = trade.timestamp;
}
});
// 计算平均值
if (analysis.totalTrades > 0) {
analysis.avgPrice = analysis.totalValue / analysis.totalVolume;
analysis.vwap = totalPriceVolume / analysis.totalVolume;
}
return analysis;
}
// 显示交易分析
displayTradeAnalysis(analysis) {
console.log('📊 交易分析报告:');
console.log('='.repeat(50));
// 基础统计
console.log('📈 基础统计:');
console.log(`总交易数: ${analysis.totalTrades}`);
console.log(`买入交易: ${analysis.buyTrades} (${(analysis.buyTrades/analysis.totalTrades*100).toFixed(1)}%)`);
console.log(`卖出交易: ${analysis.sellTrades} (${(analysis.sellTrades/analysis.totalTrades*100).toFixed(1)}%)`);
console.log(`总成交量: ${analysis.totalVolume.toFixed(4)}`);
console.log(`总成交额: ${analysis.totalValue.toFixed(2)}`);
console.log(`总手续费: ${analysis.totalFees.toFixed(4)}`);
console.log(`平均成交价: ${analysis.avgPrice.toFixed(2)}`);
console.log(`成交量加权平均价: ${analysis.vwap.toFixed(2)}`);
// 时间范围
if (analysis.timeRange.start && analysis.timeRange.end) {
const duration = analysis.timeRange.end - analysis.timeRange.start;
const days = Math.ceil(duration / (1000 * 60 * 60 * 24));
console.log(`\n⏰ 时间范围:`);
console.log(`开始时间: ${new Date(analysis.timeRange.start).toLocaleString()}`);
console.log(`结束时间: ${new Date(analysis.timeRange.end).toLocaleString()}`);
console.log(`持续时间: ${days} 天`);
console.log(`平均每天交易: ${(analysis.totalTrades / days).toFixed(1)} 笔`);
}
// 按交易对统计
console.log(`\n💱 交易对统计:`);
const sortedSymbols = Object.entries(analysis.symbolStats)
.sort(([,a], [,b]) => b.trades - a.trades);
console.log('交易对'.padEnd(12) + '交易数'.padEnd(8) + '成交量'.padEnd(15) + '成交额'.padEnd(15) + '买/卖比');
console.log('-'.repeat(65));
sortedSymbols.forEach(([symbol, stats]) => {
const buyRatio = stats.buyTrades / stats.trades;
console.log(
`${symbol.padEnd(12)}${stats.trades.toString().padEnd(8)}` +
`${stats.volume.toFixed(4).padEnd(15)}${stats.value.toFixed(2).padEnd(15)}` +
`${buyRatio.toFixed(2)}`
);
});
console.log('='.repeat(50) + '\n');
}
// 计算盈亏(简化版本)
async calculateProfitLoss(symbol) {
try {
console.log(`💰 计算 ${symbol} 盈亏情况...`);
const trades = await this.exchange.fetchMyTrades(symbol);
if (trades.length === 0) {
console.log('📭 该交易对暂无交易记录');
return null;
}
let position = 0; // 当前持仓
let totalCost = 0; // 总成本
let realizedPnL = 0; // 已实现盈亏
// 按时间排序
trades.sort((a, b) => a.timestamp - b.timestamp);
console.log('📊 逐笔分析:');
console.log('时间'.padEnd(20) + '方向'.padEnd(6) + '数量'.padEnd(12) + '价格'.padEnd(12) + '持仓'.padEnd(12) + '实现盈亏');
console.log('-'.repeat(80));
trades.forEach(trade => {
const time = new Date(trade.timestamp).toLocaleDateString();
const side = trade.side === 'buy' ? '买入' : '卖出';
if (trade.side === 'buy') {
// 买入增加持仓
position += trade.amount;
totalCost += trade.cost;
} else {
// 卖出减少持仓
if (position > 0) {
const avgCost = totalCost / position;
const sellAmount = Math.min(trade.amount, position);
const pnl = (trade.price - avgCost) * sellAmount;
realizedPnL += pnl;
position -= sellAmount;
totalCost -= avgCost * sellAmount;
console.log(
`${time.padEnd(20)}${side.padEnd(6)}` +
`${trade.amount.toFixed(4).padEnd(12)}${trade.price.toFixed(2).padEnd(12)}` +
`${position.toFixed(4).padEnd(12)}${pnl.toFixed(2)}`
);
}
}
});
// 计算未实现盈亏
let unrealizedPnL = 0;
if (position > 0) {
const currentPrice = await this.getCurrentPrice(symbol);
if (currentPrice) {
const avgCost = totalCost / position;
unrealizedPnL = (currentPrice - avgCost) * position;
}
}
const totalPnL = realizedPnL + unrealizedPnL;
console.log('\n💰 盈亏总结:');
console.log(`当前持仓: ${position.toFixed(4)}`);
console.log(`已实现盈亏: ${realizedPnL.toFixed(2)}`);
console.log(`未实现盈亏: ${unrealizedPnL.toFixed(2)}`);
console.log(`总盈亏: ${totalPnL.toFixed(2)}`);
return {
symbol,
position,
realizedPnL,
unrealizedPnL,
totalPnL,
totalTrades: trades.length,
};
} catch (error) {
console.error('❌ 计算盈亏失败:', error.message);
throw error;
}
}
// 获取当前价格
async getCurrentPrice(symbol) {
try {
const ticker = await this.exchange.fetchTicker(symbol);
return ticker.last;
} catch (error) {
console.warn(`⚠️ 获取 ${symbol} 当前价格失败: ${error.message}`);
return null;
}
}
// 交易频率分析
analyzeTradeFrequency(trades) {
if (trades.length < 2) return null;
const intervals = [];
for (let i = 1; i < trades.length; i++) {
const interval = trades[i].timestamp - trades[i-1].timestamp;
intervals.push(interval);
}
intervals.sort((a, b) => a - b);
const avgInterval = intervals.reduce((sum, interval) => sum + interval, 0) / intervals.length;
const medianInterval = intervals[Math.floor(intervals.length / 2)];
return {
avgInterval: avgInterval / (1000 * 60 * 60), // 转换为小时
medianInterval: medianInterval / (1000 * 60 * 60),
minInterval: intervals[0] / (1000 * 60), // 转换为分钟
maxInterval: intervals[intervals.length - 1] / (1000 * 60 * 60 * 24), // 转换为天
};
}
}
// 使用示例
async function tradeAnalysisExample() {
const exchange = new ccxt.binance({
apiKey: process.env.BINANCE_API_KEY,
secret: process.env.BINANCE_SECRET,
enableRateLimit: true,
sandbox: true,
});
const analyzer = new TradeHistoryAnalyzer(exchange);
try {
// 获取所有交易历史
await analyzer.fetchMyTrades(undefined, 100);
// 分析特定交易对的盈亏
// await analyzer.calculateProfitLoss('BTC/USDT');
} catch (error) {
console.error('❌ 交易分析示例失败:', error.message);
}
}
// tradeAnalysisExample();
🎯 章节总结
本章我们学习了:
✅ API认证配置
- 安全的密钥管理方法
- 沙盒环境配置
- 权限验证流程
✅ 账户余额管理
- 详细余额查询和分析
- 投资组合价值计算
- 资产分布统计
✅ 订单操作详解
- 市价订单和限价订单
- 止损订单和高级订单类型
- 订单精度处理
✅ 订单查询与管理
- 订单状态查询和监控
- 批量订单管理
- 订单历史分析
✅ 交易历史分析
- 成交记录统计
- 盈亏计算方法
- 交易频率分析
⚠️ 重要安全提醒
- 永远在沙盒环境测试 - 所有代码都应该先在测试环境验证
- 保护API密钥 - 使用环境变量,永不硬编码
- 设置合理限制 - 实施仓位管理和风险控制
- 监控异常 - 建立完善的日志和告警机制
- 小额开始 - 从小额资金开始,逐步增加
🔗 下一步
完成账户和订单管理的学习后,接下来可以:
下一章:实时数据流 (CCXT Pro)