325 lines
9.8 KiB
Python
325 lines
9.8 KiB
Python
"""
|
||
实盘交易完整流程测试脚本
|
||
|
||
测试内容:
|
||
1. 获取账户余额
|
||
2. 获取当前持仓
|
||
3. 下测试单(极小金额)
|
||
4. 查询订单状态
|
||
5. 修改止损止盈
|
||
6. 平仓
|
||
|
||
风险控制:
|
||
- 使用极小金额测试(5-10 USDT)
|
||
- 测试完成后自动平仓
|
||
"""
|
||
import sys
|
||
import os
|
||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'backend'))
|
||
|
||
import asyncio
|
||
import time
|
||
from app.services.bitget_trading_api_sdk import get_bitget_trading_api
|
||
from app.services.real_trading_service import get_real_trading_service
|
||
from app.utils.logger import logger
|
||
|
||
|
||
def print_section(title):
|
||
"""打印分隔线"""
|
||
print("\n" + "=" * 60)
|
||
print(f" {title}")
|
||
print("=" * 60)
|
||
|
||
|
||
def test_account_info(trading_api):
|
||
"""测试1: 获取账户信息"""
|
||
print_section("1. 获取账户信息")
|
||
|
||
try:
|
||
balance = trading_api.get_balance()
|
||
print(f"✅ 账户余额:")
|
||
for currency, info in balance.items():
|
||
if isinstance(info, dict):
|
||
available = info.get('available', 0)
|
||
frozen = info.get('frozen', 0)
|
||
locked = info.get('locked', 0)
|
||
if float(available) > 0 or float(frozen) > 0:
|
||
print(f" {currency}: 可用={float(available):.2f}, 冻结={float(frozen):.2f}, 锁定={float(locked):.2f}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"❌ 获取账户信息失败: {e}")
|
||
return False
|
||
|
||
|
||
def test_get_positions(trading_api):
|
||
"""测试2: 获取当前持仓"""
|
||
print_section("2. 获取当前持仓")
|
||
|
||
try:
|
||
positions = trading_api.get_position()
|
||
print(f"✅ 当前持仓数量: {len(positions)}")
|
||
|
||
open_positions = [p for p in positions if float(p.get('contracts', 0)) != 0]
|
||
if open_positions:
|
||
print(f" 活跃持仓:")
|
||
for pos in open_positions:
|
||
symbol = pos.get('symbol')
|
||
side = pos.get('side')
|
||
contracts = pos.get('contracts')
|
||
entry_price = pos.get('entryPrice')
|
||
mark_price = pos.get('markPrice')
|
||
unrealized_pnl = pos.get('unrealizedPnl', 0)
|
||
print(f" {symbol} {side} | 数量: {contracts} | 入场: {entry_price} | 标记: {mark_price} | 浮盈: {unrealized_pnl}")
|
||
else:
|
||
print(f" 当前无持仓")
|
||
|
||
return True
|
||
except Exception as e:
|
||
print(f"❌ 获取持仓失败: {e}")
|
||
return False
|
||
|
||
|
||
def test_place_order(trading_api, symbol="BTCUSDT", side='buy', size=5):
|
||
"""测试3: 下测试单"""
|
||
print_section("3. 下测试单")
|
||
|
||
# 生成订单ID
|
||
import uuid
|
||
client_order_id = f"test_{uuid.uuid4().hex[:8]}"
|
||
|
||
print(f" 交易对: {symbol}")
|
||
print(f" 方向: {side}")
|
||
print(f" 数量: {size} USDT")
|
||
print(f" 客户端ID: {client_order_id}")
|
||
|
||
try:
|
||
# 先获取当前价格
|
||
ticker = trading_api.exchange.fetch_ticker(symbol)
|
||
current_price = ticker['last']
|
||
print(f" 当前价格: ${current_price:,.2f}")
|
||
|
||
# 下市价单
|
||
print(f" 📝 正在下单...")
|
||
result = trading_api.place_order(
|
||
symbol=symbol,
|
||
side=side,
|
||
order_type='market',
|
||
size=size,
|
||
client_order_id=client_order_id
|
||
)
|
||
|
||
if result:
|
||
order_id = result.get('id')
|
||
filled_price = result.get('average') or result.get('price')
|
||
print(f"✅ 下单成功!")
|
||
print(f" 订单ID: {order_id}")
|
||
print(f" 成交价格: ${filled_price:,.2f}")
|
||
print(f" 成交数量: {size} USDT")
|
||
|
||
# 等待一下让订单完全成交
|
||
time.sleep(2)
|
||
return order_id, symbol, side
|
||
else:
|
||
print(f"❌ 下单失败: 无返回结果")
|
||
return None
|
||
except Exception as e:
|
||
print(f"❌ 下单失败: {e}")
|
||
import traceback
|
||
print(traceback.format_exc())
|
||
return None
|
||
|
||
|
||
def test_get_order(trading_api, order_id, symbol):
|
||
"""测试4: 查询订单状态"""
|
||
print_section("4. 查询订单状态")
|
||
|
||
try:
|
||
order = trading_api.exchange.fetch_order(order_id, symbol)
|
||
print(f"✅ 订单状态: {order.get('status')}")
|
||
print(f" 订单ID: {order.get('id')}")
|
||
print(f" 价格: {order.get('price')}")
|
||
print(f" 已成交: {order.get('filled')}")
|
||
print(f" 剩余: {order.get('remaining')}")
|
||
return order
|
||
except Exception as e:
|
||
print(f"❌ 查询订单失败: {e}")
|
||
return None
|
||
|
||
|
||
def test_modify_sl_tp(trading_api, symbol, side='buy'):
|
||
"""测试5: 修改止损止盈"""
|
||
print_section("5. 修改止损止盈")
|
||
|
||
# 获取当前持仓
|
||
try:
|
||
positions = trading_api.get_position()
|
||
position = None
|
||
|
||
for pos in positions:
|
||
if pos.get('symbol') == symbol and float(pos.get('contracts', 0)) != 0:
|
||
position = pos
|
||
break
|
||
|
||
if not position:
|
||
print(f"❌ 未找到 {symbol} 的持仓")
|
||
return False
|
||
|
||
# 获取当前价格来设置合理的止损止盈
|
||
ticker = trading_api.exchange.fetch_ticker(symbol)
|
||
current_price = float(ticker['last'])
|
||
|
||
if side == 'buy':
|
||
stop_loss = current_price * 0.97 # 3% 止损
|
||
take_profit = current_price * 1.05 # 5% 止盈
|
||
else:
|
||
stop_loss = current_price * 1.03 # 3% 止损
|
||
take_profit = current_price * 0.95 # 5% 止盈
|
||
|
||
print(f" 当前价格: ${current_price:,.2f}")
|
||
print(f" 设置止损: ${stop_loss:,.2f}")
|
||
print(f" 设置止盈: ${take_profit:,.2f}")
|
||
|
||
# 使用交易所API修改止损止盈(这需要根据具体交易所API实现)
|
||
# 注意: Bitget 可能需要使用不同的API来修改止损止盈
|
||
|
||
print(f"⚠️ 注意: 修改止损止盈功能需要根据交易所具体API实现")
|
||
print(f"✅ 止损止盈参数已计算(实际修改需要查看交易所API文档)")
|
||
|
||
return True
|
||
except Exception as e:
|
||
print(f"❌ 修改止损止盈失败: {e}")
|
||
import traceback
|
||
print(traceback.format_exc())
|
||
return False
|
||
|
||
|
||
def test_close_position(trading_api, symbol, side):
|
||
"""测试6: 平仓"""
|
||
print_section("6. 平仓测试")
|
||
|
||
# 获取当前持仓
|
||
try:
|
||
positions = trading_api.get_position()
|
||
position = None
|
||
|
||
for pos in positions:
|
||
if pos.get('symbol') == symbol and float(pos.get('contracts', 0)) != 0:
|
||
position = pos
|
||
break
|
||
|
||
if not position:
|
||
print(f"❌ 未找到 {symbol} 的持仓,无法平仓")
|
||
return False
|
||
|
||
contracts = float(position.get('contracts', 0))
|
||
print(f" 持仓数量: {contracts}")
|
||
|
||
# 平仓方向与开仓相反
|
||
close_side = 'sell' if side == 'buy' else 'buy'
|
||
print(f" 平仓方向: {close_side}")
|
||
|
||
# 生成平仓订单ID
|
||
import uuid
|
||
client_order_id = f"close_{uuid.uuid4().hex[:8]}"
|
||
|
||
print(f" 📝 正在平仓...")
|
||
result = trading_api.place_order(
|
||
symbol=symbol,
|
||
side=close_side,
|
||
order_type='market',
|
||
size=contracts, # 平掉所有持仓
|
||
client_order_id=client_order_id,
|
||
reduce_only=True # 只平仓,不开新仓
|
||
)
|
||
|
||
if result:
|
||
print(f"✅ 平仓成功!")
|
||
print(f" 订单ID: {result.get('id')}")
|
||
return True
|
||
else:
|
||
print(f"❌ 平仓失败: 无返回结果")
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f"❌ 平仓失败: {e}")
|
||
import traceback
|
||
print(traceback.format_exc())
|
||
return False
|
||
|
||
|
||
def main():
|
||
"""主测试流程"""
|
||
print("\n" + "🚀" * 30)
|
||
print(" 实盘交易完整流程测试")
|
||
print("🚀" * 30)
|
||
print("\n⚠️ 警告: 此测试将使用真实资金,但金额很小(5-10 USDT)")
|
||
print("⚠️ 请确保:")
|
||
print(" 1. Bitget API 配置正确")
|
||
print(" 2. 账户有足够的测试资金")
|
||
print(" 3. 使用测试网或小额资金")
|
||
|
||
# 确认开始测试
|
||
confirm = input("\n是否开始测试? (输入 'yes' 继续): ")
|
||
if confirm.lower() != 'yes':
|
||
print("测试已取消")
|
||
return
|
||
|
||
# 获取交易API
|
||
trading_api = get_bitget_trading_api()
|
||
if not trading_api:
|
||
print("❌ Bitget API 未初始化,请检查配置")
|
||
return
|
||
|
||
print(f"\n📡 交易所: {'Bitget 测试网' if trading_api.use_testnet else 'Bitget 正式网'}")
|
||
|
||
# 测试1: 获取账户信息
|
||
if not test_account_info(trading_api):
|
||
return
|
||
|
||
# 测试2: 获取当前持仓
|
||
if not test_get_positions(trading_api):
|
||
return
|
||
|
||
# 测试3: 下测试单
|
||
symbol = "BTCUSDT"
|
||
side = 'buy' # 做多
|
||
size = 5 # 5 USDT
|
||
|
||
order_result = test_place_order(trading_api, symbol, side, size)
|
||
if not order_result:
|
||
print("\n❌ 下单失败,终止测试")
|
||
return
|
||
|
||
order_id, _, _ = order_result
|
||
|
||
# 测试4: 查询订单状态
|
||
test_get_order(trading_api, order_id, symbol)
|
||
|
||
# 测试5: 修改止损止盈
|
||
test_modify_sl_tp(trading_api, symbol, side)
|
||
|
||
# 测试6: 平仓
|
||
time.sleep(2) # 等待一下
|
||
test_close_position(trading_api, symbol, side)
|
||
|
||
# 最终状态
|
||
print_section("测试完成")
|
||
print("✅ 所有测试已完成,请检查:")
|
||
print(" 1. Bitget 账户中的订单记录")
|
||
print(" 2. 余额变化")
|
||
print(" 3. 持仓情况")
|
||
|
||
# 再次获取持仓确认已平仓
|
||
test_get_positions(trading_api)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
try:
|
||
main()
|
||
except KeyboardInterrupt:
|
||
print("\n\n⚠️ 测试被用户中断")
|
||
except Exception as e:
|
||
print(f"\n\n❌ 测试出错: {e}")
|
||
import traceback
|
||
print(traceback.format_exc())
|