五、NB8 Web平台集成
五、NB8 Web平台集成
5.1 Web客户端管理
🚀 init_web_client(config)
功能: 创建并初始化WebClient,用于与Web平台通信
参数:
config: WebClient配置对象,包含以下可选字段:server_name: 字符串,策略服务器名称,用于在Web平台上标识该策略primary_balance: 浮点数,主账户初始余额,用于计算策略收益率。仅在第一次实盘初始化时需要传递,后续启动会从缓存中读取secondary_balance: 浮点数,次账户初始余额,用于双账户策略。仅在第一次实盘初始化时需要传递,后续启动会从缓存中读取open_threshold: 浮点数,开仓阈值,例如0.14表示千1.4价差开仓max_position_ratio: 浮点数,单个币种最大持仓比例,例如100表示100%,1x杠杆max_leverage: 整数,最大可用杠杆倍数funding_rate_threshold: 浮点数,资金费率阈值,例如0.1表示千1资金费率开仓cost: 浮点数,成本,主所开平 副所开平,4次交易手续费,如0.0824 代表万8.24primary_maker_fee_rate: 浮点数,主所maker手续费率primary_taker_fee_rate: 浮点数,主所taker手续费率primary_rebate_rate: 浮点数,主所返佣率secondary_maker_fee_rate: 浮点数,次所maker手续费率secondary_taker_fee_rate: 浮点数,次所taker手续费率secondary_rebate_rate: 浮点数,次所返佣率
返回值: 无
示例:
# 初始化Web客户端
web_config = {
"server_name": "BTC-ETH套利策略",
"primary_balance": 10000.0, # 主账户初始余额
"secondary_balance": 5000.0, # 次账户初始余额
"open_threshold": 0.14, # 开仓阈值 (千1.4价差)
"max_position_ratio": 100, # 最大持仓比例 (100%)
"max_leverage": 3, # 最大杠杆倍数
"funding_rate_threshold": 0.1, # 资金费率阈值 (千1)
"cost": 0.0824, # 交易成本 (万8.24)
"primary_maker_fee_rate": 0.0002, # 主所maker费率
"primary_taker_fee_rate": 0.0005, # 主所taker费率
"primary_rebate_rate": 0.3, # 主所返佣率
"secondary_maker_fee_rate": 0.0002, # 次所maker费率
"secondary_taker_fee_rate": 0.0005, # 次所taker费率
"secondary_rebate_rate": 0.7, # 次所返佣率
}
trader.init_web_client(web_config)
▶️ start_web_client(upload_interval=None)
功能: 启动WebClient,开始定期向Web平台上传数据
参数:
upload_interval: 上传间隔(秒,s),默认为5秒。此参数控制向Web平台发送数据的频率。
返回值: 无
示例:
# 启动Web客户端,设置10秒上传间隔
trader.start_web_client(upload_interval=10)
⏹️ stop_web_client()
功能: 停止WebClient,确保最后一批数据上传
参数: 无
返回值: 无
示例:
# 策略结束时停止Web客户端
trader.stop_web_client()
5.2 策略状态检查
这些方法用于检查NB8 Web平台下发的策略控制指令,可用于策略程序中实现对平台实时指令的响应。
🚫 is_web_soft_stopped()
功能: 检查平台是否下发了缓停指令
参数: 无
返回值:
- 布尔值,为true时表示平台要求策略缓慢停止交易
说明:
- 此状态表示平台要求策略在合适的时机停止交易
- 策略可以完成当前交易流程,但不应开始新的交易周期
🔒 is_web_opening_stopped()
功能: 检查平台是否下发了停止开仓指令
参数: 无
返回值:
- 布尔值,为true时表示平台要求策略停止开新仓
说明:
- 此状态表示平台要求策略不再开设新的仓位
- 策略可以继续管理现有仓位,包括平仓操作
🔓 is_web_force_closing()
功能: 检查平台是否下发了强平指令
参数: 无
返回值:
- 布尔值,为true时表示平台要求策略强制平仓
说明:
- 此状态表示平台要求策略立即平掉所有持仓
- 策略应在检测到此状态为true时执行平仓逻辑
示例:
# 检查平台控制指令
def check_platform_control():
# 检查是否需要缓停交易
if trader.is_web_soft_stopped():
print("平台已发出缓停指令,将不再开始新的交易周期")
return "soft_stop"
# 检查是否禁止开仓
if trader.is_web_opening_stopped():
print("平台已禁止开仓,仅允许管理现有仓位")
return "no_open"
# 检查是否需要强制平仓
if trader.is_web_force_closing():
print("平台已发出强平指令,执行紧急平仓流程")
close_all_positions()
return "force_close"
return "normal"
# 交易主循环
def trading_loop():
import time
while True:
# 检查平台状态
status = check_platform_control()
if status == "force_close":
# 等待平仓完成后退出
break
elif status == "soft_stop":
# 完成当前周期后退出
time.sleep(60)
break
elif status == "no_open":
# 只管理现有仓位,不开新仓
manage_positions()
else:
# 正常交易
scan_opportunities()
time.sleep(5)
5.3 账户与余额数据
💰 update_total_balance(primary_balance, secondary_balance=None, available_primary=None, available_secondary=None)
功能: 更新账户余额信息到Web平台
参数:
primary_balance: 主账户总余额secondary_balance: 次账户总余额,可选available_primary: 主账户可用余额,可选available_secondary: 次账户可用余额,可选
返回值: 无
示例:
# 更新账户余额信息
def update_balance_info():
# 查询主账户余额
primary_cmd = {
"account_id": 0,
"method": "UsdtBalance",
"sync": True
}
primary_result = trader.publish(primary_cmd)
primary_balance = primary_result.get("balance", 0)
available_primary = primary_result.get("available", 0)
# 查询次账户余额
secondary_cmd = {
"account_id": 1,
"method": "UsdtBalance",
"sync": True
}
secondary_result = trader.publish(secondary_cmd)
secondary_balance = secondary_result.get("balance", 0)
available_secondary = secondary_result.get("available", 0)
# 更新到Web平台
trader.update_total_balance(
primary_balance,
secondary_balance,
available_primary,
available_secondary
)
print(f"已更新余额信息 - 主账户: {primary_balance} (可用: {available_primary}), 次账户: {secondary_balance} (可用: {available_secondary})")
💱 add_funding_fee(primary_fee=None, secondary_fee=None)
功能: 添加已结算的资金费用记录到Web平台
参数:
primary_fee: 主账户已结算资金费,可选secondary_fee: 次账户已结算资金费,可选
返回值: 无
💱 update_pred_funding(primary_fee=None, secondary_fee=None)
功能: 更新未结算的预测资金费用记录到Web平台
参数:
primary_fee: 主账户未结算预测资金费,可选secondary_fee: 次账户未结算预测资金费,可选
返回值: 无
示例:
# 记录资金费
def record_funding_fee():
# 添加已结算的资金费
trader.add_funding_fee(primary_fee=-1.25, secondary_fee=-0.85)
# 更新未结算的预测资金费
trader.update_pred_funding(primary_fee=-0.33, secondary_fee=-0.17)
print("已记录资金费信息")
# 资金费率定时结算处理函数示例
def handle_funding_settlement():
import time
# 获取已结算的资金费数据(示例)
# 实际使用时应从交易所API获取真实数据
primary_settled_fee = -2.35
secondary_settled_fee = -1.15
# 记录已结算资金费
trader.add_funding_fee(
primary_fee=primary_settled_fee,
secondary_fee=secondary_settled_fee
)
# 获取未结算的预测资金费(示例)
primary_predicted_fee = -0.45
secondary_predicted_fee = -0.21
# 更新未结算预测资金费
trader.update_pred_funding(
primary_fee=primary_predicted_fee,
secondary_fee=secondary_predicted_fee
)
# 记录结算时间
settlement_time = int(time.time())
print(f"在 {settlement_time} 处理了资金费结算")
5.4 持仓与盈亏数据
📈 update_total_position_value(total_value, long_position_value, short_position_value)
功能: 更新所有节点持仓价值信息到Web平台
参数:
total_value: 所有节点总持仓价值long_position_value: 所有节点多头持仓价值short_position_value: 所有节点空头持仓价值
返回值: 无
📈 update_current_position_value(total_value, long_position_value, short_position_value)
功能: 更新当前节点持仓价值信息到Web平台
参数:
total_value: 当前节点总持仓价值long_position_value: 当前节点多头持仓价值short_position_value: 当前节点空头持仓价值
返回值: 无
📊 update_floating_profit(floating_profit)
功能: 更新浮动盈亏信息到Web平台
参数:
floating_profit: 浮动盈亏金额
返回值: 无
💹 log_profit(profit)
功能: 上传利润,前端实盘页用来展示利润曲线
参数:
profit: 利润金额
返回值: 无
示例:
# 更新持仓信息
def update_position_info():
# 计算当前节点持仓价值
current_total = 15000.0
current_long = 10000.0
current_short = 5000.0
trader.update_current_position_value(current_total, current_long, current_short)
# 更新所有节点总持仓价值
total_value = 25000.0
total_long = 15000.0
total_short = 10000.0
trader.update_total_position_value(total_value, total_long, total_short)
# 更新浮动盈亏
floating_profit = 320.5
trader.update_floating_profit(floating_profit)
# 记录策略利润曲线数据点
profit = 1580.75
trader.log_profit(profit)
print("已更新持仓与盈亏信息")
# 从实际持仓数据计算持仓价值
def calculate_position_values(positions):
total_value = 0
long_value = 0
short_value = 0
# 获取当前市场价格(示例)
# 实际使用时应从交易所API获取最新价格
market_prices = {
"BTC_USDT": 51200.5,
"ETH_USDT": 3250.8,
"SOL_USDT": 115.25
}
# 计算持仓价值
for pos in positions:
symbol = pos["symbol"]
amount = pos["amount"]
side = pos["side"]
# 获取当前价格
current_price = market_prices.get(symbol, 0)
if current_price == 0:
continue
# 计算持仓价值
position_value = amount * current_price
total_value += position_value
# 根据方向累加多空持仓价值
if side == "long":
long_value += position_value
else:
short_value += position_value
# 更新到Web平台
trader.update_current_position_value(total_value, long_value, short_value)
# 返回计算结果
return {
"total": total_value,
"long": long_value,
"short": short_value
}
5.5 交易统计数据
📉 update_trade_stats(maker_volume, taker_volume, profit, is_single_close=False)
功能: 更新交易统计数据到Web平台
参数:
maker_volume: 挂单量 不传默认0taker_volume: 吃单量 不传默认0profit: 总利润。注意: 未平仓时传入0,此时系统只会统计交易量,不会统计盈利次数is_single_close: 是否单腿平仓,默认False
💡 提示: 当策略仅开仓但未平仓时,应调用此方法并将
profit参数设为0。这样系统会记录交易量,但不会增加盈利/亏损次数统计。当交易完全结束(开仓并平仓)后,再传入实际的盈亏金额进行完整统计。
返回值:
- 总利润
示例:
# 开仓时,只记录交易量,不计算盈亏
def record_opening_trade(maker_vol, taker_vol):
result = trader.update_trade_stats(maker_vol, taker_vol, 0)
if "Ok" in result:
total_profit = result["Ok"]
print(f"已记录开仓交易量,不计入盈亏,当前总利润: {total_profit}")
return total_profit
else:
error = result.get("Err", "未知错误")
print(f"记录开仓交易失败: {error}")
return None
# 平仓时,记录交易量并更新盈亏
def record_closing_trade(maker_vol, taker_vol, profit, is_single=False):
result = trader.update_trade_stats(maker_vol, taker_vol, profit, is_single)
if "Ok" in result:
total_profit = result["Ok"]
print(f"已记录平仓交易,利润: {profit},当前总利润: {total_profit}")
return total_profit
else:
error = result.get("Err", "未知错误")
print(f"记录平仓交易失败: {error}")
return None
# 实际使用示例
def handle_trade_execution(trade_type, volumes, profit=None):
maker_volume = volumes.get("maker", 0)
taker_volume = volumes.get("taker", 0)
if trade_type == "open":
# 开仓只记录交易量
record_opening_trade(maker_volume, taker_volume)
elif trade_type == "close":
# 平仓记录交易量和盈亏
record_closing_trade(maker_volume, taker_volume, profit or 0)
elif trade_type == "single_close":
# 单腿平仓
record_closing_trade(maker_volume, taker_volume, profit or 0, True)
📊 get_stats()
功能: 获取当前完整的统计数据
参数: 无
返回值:
- 包含统计数据的Python字典,使用原始字段名(而非序列化别名)
返回字段说明:
-
time: 起始时间 -
server_name: 服务器名称 -
账户余额信息
initial_balance: 主所起始余额current_balance: 主所当前余额secondary_initial_balance: 次所初始余额secondary_current_balance: 次所实时余额available_balance: 主所可用余额secondary_available_balance: 次所可用余额
-
交易统计
volume: 累计交易量maker_volume: 累计maker交易量taker_volume: 累计taker交易量count: 总套利次数win_rate: 胜率total_profit: 总利润success_count: 成功次数success_profit: 成功利润failure_count: 失败次数failure_loss: 失败亏损unrealized_pnl: 未实现盈亏single_close_count: 单腿平仓次数single_close_profit: 单腿平仓金额
-
持仓和杠杆信息
total_position_value: 所有节点持仓杠杆total_long_position_value: 所有节点多仓杠杆total_short_position_value: 所有节点空仓杠杆current_position_value: 当前节点持仓杠杆current_long_position_value: 当前节点多仓杠杆current_short_position_value: 当前节点空仓杠杆
-
资金费率与回报率
funding_fee: 当日已结算的资金费总额primary_funding_fee: 当日已结算的主所资金费secondary_funding_fee: 当日已结算的次所资金费
-
交易参数
cost: 成本open_threshold: 开仓阈值,如0.14代表千1.4价差开仓funding_rate_threshold: 资金费率阈值,如0.1代表千1资金费率开仓max_position_ratio: 单个币种最大持仓比例,如100代表100%,1x杠杆fund_transfer: 资金划转max_leverage: 最大可开杠杆primary_maker_fee_rate: 主所maker手续费率primary_taker_fee_rate: 主所taker手续费率primary_rebate_rate: 主所返佣率secondary_maker_fee_rate: 次所maker手续费率secondary_taker_fee_rate: 次所taker手续费率secondary_rebate_rate: 次所返佣率
-
今日数据
today: 今日统计数据对象,包含以下字段:time: 当日起始时间戳initial_balance: 当日初始主所余额current_balance: 当日当前主所余额available_balance: 当日主所可用余额secondary_initial_balance: 当日初始次所余额secondary_current_balance: 当日当前次所余额secondary_available_balance: 当日次所可用余额volume: 当日交易量maker_volume: 当日maker交易量taker_volume: 当日taker交易量count: 当日套利次数win_rate: 当日胜率total_profit: 当日总利润success_count: 当日成功次数success_profit: 当日成功利润failure_count: 当日失败次数failure_loss: 当日失败亏损funding_fee: 未结算的预测资金费总额primary_funding_fee: 未结算的预测主所资金费secondary_funding_fee: 未结算的预测次所资金费
示例:
# 获取并分析统计数据
def analyze_trading_stats():
# 获取完整统计数据
result = trader.get_stats()
if "Ok" in result:
stats = result["Ok"]
else:
error = result.get("Err", "未知错误")
print(f"获取统计数据失败: {error}")
return None
# 提取关键指标
server_name = stats.get("server_name", "未命名策略")
win_rate = stats.get("win_rate", 0) * 100 # 转换为百分比
total_trades = stats.get("count", 0)
success_trades = stats.get("success_count", 0)
failure_trades = stats.get("failure_count", 0)
total_profit = stats.get("total_profit", 0)
total_volume = stats.get("volume", 0)
# 分析统计数据
print(f"策略 '{server_name}' 统计分析:")
print(f"总交易次数: {total_trades} (成功: {success_trades}, 失败: {failure_trades})")
print(f"胜率: {win_rate:.2f}%")
print(f"总盈利: {total_profit:.2f} USDT")
print(f"总交易量: {total_volume:.2f} USDT")
# 计算平均每笔交易盈亏
if total_trades > 0:
avg_profit_per_trade = total_profit / total_trades
print(f"平均每笔交易盈亏: {avg_profit_per_trade:.2f} USDT")
# 获取当日数据
today_stats = stats.get("today", {})
today_profit = today_stats.get("total_profit", 0)
today_trades = today_stats.get("count", 0)
today_win_rate = today_stats.get("win_rate", 0) * 100
print(f"\n今日统计:")
print(f"今日交易次数: {today_trades}")
print(f"今日胜率: {today_win_rate:.2f}%")
print(f"今日盈利: {today_profit:.2f} USDT")
# 返回关键指标
return {
"win_rate": win_rate,
"total_profit": total_profit,
"total_trades": total_trades,
"today_profit": today_profit
}
5.6 数据可视化
📊 upload_tables(tables)
功能: 上传多个表格数据到Web平台显示
参数:
tables: 表格数据列表,每个表格包含标题、列和行数据
返回值: 无
示例:
# 上传表格数据到Web平台显示
def upload_market_data():
# 价差表
spread_table = {
"title": "交易所价差表",
"cols": ["交易对", "交易所A价格", "交易所B价格", "价差(‰)", "资金费率A", "资金费率B"],
"rows": [
["BTC_USDT", "50120.5", "50080.2", "0.81", "0.01%", "-0.025%"],
["ETH_USDT", "3245.8", "3240.5", "1.63", "0.008%", "-0.01%"],
["SOL_USDT", "110.25", "109.85", "3.64", "0.015%", "-0.02%"],
["BNB_USDT", "415.8", "415.2", "1.44", "0.005%", "-0.015%"]
]
}
# 持仓表
position_table = {
"title": "当前持仓",
"cols": ["交易对", "方向", "数量", "开仓价", "当前价", "浮动盈亏", "持仓时间"],
"rows": [
["BTC_USDT", "多/空", "0.15", "49850", "50100", "+$37.5", "2小时15分"],
["ETH_USDT", "多/空", "1.2", "3210", "3245", "+$42", "1小时30分"]
]
}
# 上传表格数据到Web平台
trader.upload_tables([spread_table, position_table])
print("已更新Web平台数据表格")
# 创建交易机会表格
def create_opportunity_table(opportunities):
table = {
"title": "套利机会",
"cols": ["交易对", "交易所A", "交易所B", "价差(‰)", "预期收益", "资金费差"],
"rows": []
}
# 添加行数据
for opp in opportunities:
row = [
opp["symbol"],
opp["exchange_a"],
opp["exchange_b"],
f"{opp['spread']:.2f}",
f"{opp['expected_profit']:.2f} USDT",
f"{opp['funding_diff']:.4f}%"
]
table["rows"].append(row)
return table
# 示例:定期更新多个表格
def update_dashboard_tables():
import time
# 获取套利机会(示例数据)
opportunities = [
{"symbol": "BTC_USDT", "exchange_a": "Binance", "exchange_b": "OKX",
"spread": 1.25, "expected_profit": 18.5, "funding_diff": 0.035},
{"symbol": "ETH_USDT", "exchange_a": "Binance", "exchange_b": "OKX",
"spread": 2.10, "expected_profit": 12.8, "funding_diff": 0.025}
]
# 获取持仓情况(示例数据)
positions = [
{"symbol": "BTC_USDT", "side": "多/空", "amount": 0.15,
"entry_price": 49850, "current_price": 50100, "pnl": 37.5, "duration": "2小时15分"},
{"symbol": "ETH_USDT", "side": "多/空", "amount": 1.2,
"entry_price": 3210, "current_price": 3245, "pnl": 42, "duration": "1小时30分"}
]
# 创建机会表格
opportunity_table = create_opportunity_table(opportunities)
# 创建持仓表格
position_table = {
"title": "当前持仓",
"cols": ["交易对", "方向", "数量", "开仓价", "当前价", "浮动盈亏", "持仓时间"],
"rows": []
}
for pos in positions:
row = [
pos["symbol"],
pos["side"],
str(pos["amount"]),
str(pos["entry_price"]),
str(pos["current_price"]),
f"+${pos['pnl']}" if pos['pnl'] >= 0 else f"-${abs(pos['pnl'])}",
pos["duration"]
]
position_table["rows"].append(row)
# 上传到Web平台
trader.upload_tables([opportunity_table, position_table])
print(f"已在 {int(time.time())} 更新仪表盘数据")
5.7 账户强停功能
🛑 set_force_stop(force_stop)
功能: 直接设置实盘强停状态
参数:
force_stop: 布尔值,True表示启用强停状态,False表示解除强停状态
返回值: 无
使用场景:
- 策略亏损过多需要暂停开仓一段时间进行风控
- 发现异常行情,需要紧急暂停交易
- 系统检测到风险预警,需要暂停策略执行
使用示例:
# 启用强停状态
def enable_force_stop():
"""设置实盘强停状态"""
trader.set_force_stop(True)
trader.log("已启用账户强停状态", level="WARN", color="red")
# 解除强停状态
def disable_force_stop():
"""解除实盘强停状态"""
trader.set_force_stop(False)
trader.log("已解除账户强停状态", level="INFO", color="green")
# 根据条件自动管理强停状态
def manage_force_stop():
"""根据策略状态自动管理强停状态"""
# 获取统计数据
result = trader.get_stats()
if "Ok" in result:
stats = result["Ok"]
# 检查最大回撤是否超过阈值
max_drawdown = stats.get('max_drawdown', 0.0)
if max_drawdown < -15.0: # 回撤超过15%
trader.set_force_stop(True)
trader.log(f"检测到回撤{max_drawdown:.2f}%超过阈值,已启用强停状态", level="WARN", color="red")
else:
# 如果回撤恢复正常,可以解除强停
trader.set_force_stop(False)
trader.log("回撤状态正常,已解除强停状态", level="INFO")
else:
error = result.get("Err", "未知错误")
trader.log(f"获取统计数据失败: {error}", level="ERROR", color="red")
注意事项:
- 此方法直接设置实盘强停状态,比通过表格内容中添加"账户强停"字段更加直接高效
- 强停状态只影响Web平台上的显示,不会自动停止策略的实际执行,需要在策略代码中主动检测并处理强停状态
- 建议在策略的主循环中定期检查并管理强停状态