策略源码
import time
import math
import json
import traceback
from decimal import Decimal, ROUND_DOWN, ROUND_HALF_UP, getcontext
# 全局变量初始化
AXMNIYHRBU = 0 # 上一次处理的K线时间戳
AXMNLQXHRBU = 0 # 上轨价格
AQDVNLQXHRBU = 0 # 下轨价格
AQDVNQXHRBU = 0 # 合约面值
ABAVGBA = 0 # 交易数量
# 交易信号持久化变量
active_signal = None # 当前活跃的交易信号 "long", "short" 或 None
signal_start_time = 0 # 信号开始时间
signal_duration = 120 # 信号持续时间(秒),2分钟
# 未在代码中定义的全局变量(可能是策略参数)
# 这些变量在FMZ平台中可能通过界面配置
AXXAIMBRBU = 34 # 计算ATR的周期,需要根据实际情况设置
AXXAIMHRBU = 1 # 通道宽度系数,需要根据实际情况设置
AXXBZMBRBU = 10 # 资金管理相关参数,需要根据实际情况设置
AXXAIYHRBU = 10 # 杠杆倍数,需要根据实际情况设置
# Avellaneda-Stoikov模型参数
GAMMA = 0.1 # 风险厌恶系数
SIGMA = 0.01 # 波动率估计
T = 1.0/24 # 时间周期(1小时)
# 订单管理
pending_orders = {} # 存储挂单信息 {order_id: {'time': 下单时间, 'type': 订单类型, 'price': 价格, 'amount': 数量}}
# 止损相关全局变量
STOP_LOSS_PERCENT = 1.0 # 止损百分比,默认5%
STOP_LOSS_RETRY_TIMES = 120 # 止损订单重试次数
STOP_LOSS_WAIT_SECONDS = 2 # 止损订单等待时间(秒)
stop_loss_orders = {} # 存储止损订单信息 {order_id: {'time': 下单时间, 'type': 订单类型, 'price': 价格, 'amount': 数量, 'retry_count': 重试次数}}
entry_prices = {} # 存储入场价格 {'long': 价格, 'short': 价格}
# 止损后暂停相关变量
COOLDOWN_DURATION_SECONDS = 40 * 60 # 止损冷却期时长(秒),例如40分钟
g_stop_loss_cooldown_end_time = 0 # 记录止损冷却期结束的时间戳,0表示无冷却期
is_paused_after_stop_loss = False # 策略是否因止损而处于冷却暂停状态
is_stop_loss_order_pending = False # 新增:表示是否有止损订单正在挂单或处理中
# FMZ平台常量定义
PD_LONG = 0 # 多头持仓类型常量
PD_SHORT = 1 # 空头持仓类型常量
# 设置Decimal精度
getcontext().prec = 18
# 合约参数
contract_details = None
price_precision = 2 # 默认价格精度,会被合约详情覆盖
amount_precision = 4 # 默认数量精度,会被合约详情覆盖
maker_buffer_ticks = 1 # 开仓缓冲(几个最小价格单位)
close_maker_buffer_ticks = 1 # 平仓缓冲(几个最小价格单位,更大以确保成功)
def AQTONQXHRBU(AXBONQXHRBU):
ABABA = []
for i in range(1, len(AXBONQXHRBU)):
AAAA = AXBONQXHRBU[i - 1]['Close']
AAAAA = AXBONQXHRBU[i]['High']
AAABA = AXBONQXHRBU[i]['Low']
ABABA1 = AAAAA - AAABA
ABABA2 = abs(AAAAA - AAAA)
ABABA3 = abs(AAABA - AAAA)
ABABA.append(max(ABABA1, ABABA2, ABABA3))
return ABABA
def AQNONQXHRBU(ABCAVGBA, ABCCVGBA):
if len(ABCAVGBA) < ABCCVGBA:
return float('nan')
ABBNVGBA = sum(ABCAVGBA[-ABCCVGBA:])
return ABBNVGBA / ABCCVGBA
def calculate_optimal_price(mid_price, inventory, side):
inventory_risk = GAMMA * SIGMA * SIGMA * inventory
time_factor = SIGMA * SIGMA * T / GAMMA
if side == "buy":
optimal_price = mid_price - time_factor/2 - inventory_risk
else:
optimal_price = mid_price + time_factor/2 - inventory_risk
if side == "buy" and optimal_price >= mid_price:
optimal_price = mid_price * 0.9995
elif side == "sell" and optimal_price <= mid_price:
optimal_price = mid_price * 1.0005
return _N(optimal_price, price_precision)
def calculate_stop_loss_price(position_type, entry_price, current_price, inventory):
mid_price = current_price
if position_type == "long":
optimal_price = calculate_optimal_price(mid_price, inventory, "sell")
tick_size = Decimal('1e-' + str(price_precision))
buffer_amount = close_maker_buffer_ticks * tick_size
buffered_price = Decimal(str(optimal_price)) + buffer_amount
stop_price_rounded = (buffered_price / tick_size).to_integral_value(rounding=ROUND_HALF_UP) * tick_size
stop_price = float(stop_price_rounded)
else:
optimal_price = calculate_optimal_price(mid_price, inventory, "buy")
tick_size = Decimal('1e-' + str(price_precision))
buffer_amount = close_maker_buffer_ticks * tick_size
buffered_price = Decimal(str(optimal_price)) - buffer_amount
stop_price_rounded = (buffered_price / tick_size).to_integral_value(rounding=ROUND_DOWN) * tick_size
stop_price = float(stop_price_rounded)
Log(f"止损价格计算详情 - 持仓:{position_type} 入场价:{entry_price} 当前价:{current_price} 最优价:{optimal_price} 缓冲后:{float(buffered_price)} 最终价格:{stop_price}")
return stop_price
def calculate_stop_loss_threshold(position_type, entry_price):
if entry_price is None or entry_price == 0:
return None
if position_type == "long":
stop_price = entry_price * (1 - STOP_LOSS_PERCENT / 100)
else:
stop_price = entry_price * (1 + STOP_LOSS_PERCENT / 100)
return _N(stop_price, price_precision)
def check_stop_loss_condition(position_type, entry_price, current_price):
"""
检查是否触发止损条件
参数:
position_type: 持仓类型 ("long" 或 "short")
entry_price: 入场价格
current_price: 当前价格
返回:
布尔值,表示是否触发止损
"""
if entry_price is None or entry_price == 0:
return False
if position_type == "long":
stop_price = entry_price * (1 - STOP_LOSS_PERCENT / 100)
return current_price <= stop_price
else:
stop_price = entry_price * (1 + STOP_LOSS_PERCENT / 100)
return current_price >= stop_price
def execute_stop_loss(position_type, amount, current_price, inventory):
"""
执行止损操作
参数:
position_type: 持仓类型 ("long" 或 "short")
amount: 持仓数量
current_price: 当前价格
inventory: 当前库存(正值表示多头,负值表示空头)
返回:
订单ID或None
"""
global stop_loss_pause_until, is_paused_after_stop_loss
entry_price = entry_prices.get(position_type)
if entry_price is None:
Log(f"警告: 无法获取{position_type}持仓的入场价格,使用当前价格")
entry_price = current_price
stop_price = calculate_stop_loss_price(position_type, entry_price, current_price, inventory)
if position_type == "long":
direction = "sell"
else:
direction = "buy"
Log(f"执行{position_type}持仓止损,方向:{direction} 价格:{stop_price} 数量:{amount}")
order_id = place_post_only_order(direction, stop_price, amount, is_close=True)
if order_id:
stop_loss_orders[order_id] = {
'time': time.time(),
'type': direction,
'price': stop_price,
'amount': amount,
'retry_count': 0,
'position_type': position_type
}
global is_stop_loss_order_pending
is_stop_loss_order_pending = True
return order_id
def check_and_handle_stop_loss_orders():
"""
检查止损订单状态,处理未成交的止损订单。
当止损成功平仓或重试次数过多时,设置策略进入冷却暂停状态。
"""
global is_paused_after_stop_loss, g_stop_loss_cooldown_end_time
global is_stop_loss_order_pending
current_time = time.time()
orders_to_retry = []
for order_id, order_info in list(stop_loss_orders.items()):
position_type = order_info.get("position_type")
has_position = check_actual_position(position_type) if position_type else False
if position_type and not has_position:
Log(f"止损订单 {order_id} 已成交且对应{position_type}仓位已平")
del stop_loss_orders[order_id]
is_paused_after_stop_loss = True
g_stop_loss_cooldown_end_time = current_time + COOLDOWN_DURATION_SECONDS
is_stop_loss_order_pending = False
Log(f"检测到止损成功,策略进入冷却暂停状态,冷却期至: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(g_stop_loss_cooldown_end_time))}")
continue
if current_time - order_info["time"] > STOP_LOSS_WAIT_SECONDS:
orders_to_retry.append((order_id, order_info))
for order_id, order_info in orders_to_retry:
try:
details = get_contract_details()
if not details:
Log("错误: 无法获取合约详情,取消止损订单失败")
continue
parts = order_id.split(",")
if len(parts) != 2:
Log(f"错误: 无效的订单ID格式: {order_id}")
continue
contract = parts[0]
actual_order_id = parts[1]
settle = details["settle"]
Log(f"取消超时止损订单 {order_id}")
exchange.IO("api", "DELETE", f"/api/v4/futures/{settle}/orders/{actual_order_id}", "")
if order_id in stop_loss_orders:
del stop_loss_orders[order_id]
ticker = exchange.GetTicker()
position = exchange.GetPosition()
if not ticker or not position or len(position) == 0:
Log("无法获取行情或持仓,跳过重试")
continue
position_type = "long" if position[0]["Type"] == PD_LONG else "short"
position_amount = position[0]["Amount"]
entry_price = entry_prices.get(position_type, position[0]["Price"])
inventory = position_amount if position_type == "long" else -position_amount
new_stop_price = calculate_stop_loss_price(
position_type,
entry_price,
ticker.Last,
inventory
)
direction = "sell" if position_type == "long" else "buy"
Log(f"重试止损订单 - 方向:{direction} 价格:{new_stop_price} 数量:{position_amount}")
new_order_id = place_post_only_order(
direction,
new_stop_price,
position_amount,
is_close=True
)
if new_order_id:
stop_loss_orders[new_order_id] = {
"time": time.time(),
"type": direction,
"price": new_stop_price,
"amount": position_amount,
"retry_count": order_info.get("retry_count", 0) + 1,
"position_type": position_type
}
if stop_loss_orders[new_order_id]["retry_count"] > STOP_LOSS_RETRY_TIMES:
Log(f"止损订单重试次数超过{STOP_LOSS_RETRY_TIMES}次,策略进入冷却暂停模式")
is_paused_after_stop_loss = True
g_stop_loss_cooldown_end_time = current_time + COOLDOWN_DURATION_SECONDS
is_stop_loss_order_pending = False
Log(f"策略进入冷却暂停状态,冷却期至: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(g_stop_loss_cooldown_end_time))}")
except Exception as e:
Log(f"处理止损订单异常: {e}")
Log(f"详细错误: {traceback.format_exc()}")
def get_contract_details():
"""
获取合约详情
返回:
合约详情字典或None
"""
global contract_details, price_precision, amount_precision
if contract_details:
return contract_details
try:
Log("正在获取合约详情...")
currency_pair = exchange.GetCurrency()
settle_currency = "usdt"
futures_contract = f"{currency_pair}"
api_path = f"/api/v4/futures/{settle_currency}/contracts/{futures_contract}"
Log(f"调用API获取合约详情: {api_path}")
details_response = exchange.IO("api", "GET", api_path, "")
if details_response is None or details_response == "<nil>" or details_response == "":
Log(f"错误: 获取合约详情失败,返回空值")
return None
if isinstance(details_response, str):
try:
details = json.loads(details_response)
except Exception as e:
Log(f"错误: 解析合约详情响应失败: {e}")
return None
elif isinstance(details_response, dict):
details = details_response
else:
Log(f"错误: 合约详情响应格式不正确: {type(details_response)}")
return None
if 'quanto_multiplier' in details and 'order_size_min' in details and 'order_price_round' in details:
quanto_multiplier = Decimal(str(details['quanto_multiplier']))
order_size_min = Decimal(str(details['order_size_min']))
price_precision_str = details['order_price_round']
if '.' in price_precision_str:
price_precision = len(price_precision_str.split('.')[-1])
else:
price_precision = 0
Log(f"从合约获取的价格精度: {price_precision} (来自 {price_precision_str})")
contract_value_base = quanto_multiplier
if contract_value_base <= 0 or order_size_min <= 0:
Log(f"错误: 合约 {futures_contract} 的 contract_value_base 或 order_size_min 无效")
return None
contract_details = {
'contract_value_base': contract_value_base,
'order_size_min': order_size_min,
'price_precision': price_precision,
'contract': futures_contract,
'settle': settle_currency
}
Log(f"获取到合约详情: {contract_details}")
return contract_details
else:
Log(f"错误: 合约详情缺少必要字段")
return None
except Exception as e:
Log(f"获取合约详情异常: {e}")
Log(f"详细错误: {traceback.format_exc()}")
return None
def check_actual_position(position_type):
"""
直接查询交易所API获取实际持仓状态
参数:
position_type: 持仓类型 ("long" 或 "short")
返回:
布尔值,表示是否有指定类型的持仓
"""
try:
details = get_contract_details()
if not details:
Log("错误: 无法获取合约详情,无法检查持仓状态")
return False
settle = details['settle']
contract = details['contract']
api_path = f"/api/v4/futures/{settle}/positions"
Log(f"尝试通过exchange.IO直接查询持仓状态。路径: {api_path}")
raw_response = exchange.IO("api", "GET", api_path, "")
if raw_response is None or raw_response == "<nil>" or raw_response == "":
Log(f"信息: 持仓查询返回空值,可能无持仓")
return False
positions = None
if isinstance(raw_response, str):
try:
positions = json.loads(raw_response)
except Exception as e:
Log(f"错误: 解析持仓响应失败: {e}")
return False
elif isinstance(raw_response, list):
positions = raw_response
else:
Log(f"错误: 持仓响应格式不正确: {type(raw_response)}")
return False
for pos in positions:
if isinstance(pos, dict) and pos.get('contract') == contract:
size = float(pos.get('size', 0))
if position_type == "long" and size > 0:
Log(f"交易所确认有多仓: {size}")
return True
elif position_type == "short" and size < 0:
Log(f"交易所确认有空仓: {size}")
return True
Log(f"交易所确认无{position_type}仓位")
return False
except Exception as e:
Log(f"检查持仓状态异常: {e}")
Log(f"详细错误: {traceback.format_exc()}")
return False
def check_and_set_position_mode():
"""
检查并设置单向持仓模式
"""
try:
api_path = "/api/v4/futures/usdt/position_mode"
response = exchange.IO("api", "GET", api_path, "")
if response is None or response == "<nil>" or response == "":
Log("警告: 无法获取当前持仓模式")
return
mode_info = None
if isinstance(response, str):
try:
mode_info = json.loads(response)
except Exception as e:
Log(f"解析持仓模式响应失败: {e}")
return
elif isinstance(response, dict):
mode_info = response
if mode_info and mode_info.get("mode") != "single":
Log("当前不是单向持仓模式,正在切换...")
set_response = exchange.IO("api", "POST", api_path, "mode=single")
Log(f"切换持仓模式结果: {set_response}")
Log("已成功切换为单向持仓模式")
else:
Log("当前已是单向持仓模式,无需切换")
except Exception as e:
Log(f"检查持仓模式异常: {e}")
Log(f"详细错误: {traceback.format_exc()}")
def place_post_only_order(direction, price, amount, is_close=False):
"""
下Post-Only限价单 - 使用size正负值控制方向
参数:
direction: 交易方向 ("buy" 或 "sell")
price: 价格
amount: 数量
is_close: 是否平仓
返回:
订单ID或None
"""
try:
# 获取合约详情
details = get_contract_details()
if not details:
Log("错误: 无法获取合约详情,下单失败")
return None
if direction == "buy":
size = amount # 正数表示买入/做多
else: # "sell"
size = -amount # 负数表示卖出/做空
contract = details['contract']
settle = details['settle']
api_path = f"/api/v4/futures/{settle}/orders"
params = {
"contract": contract,
"size": str(size),
"price": str(price),
"tif": "poc" # Post-Only
}
if is_close:
params["reduce_only"] = "true"
params_items = []
for key, value in params.items():
params_items.append(f"{key}={value}")
params_str = "&".join(params_items)
Log(f"尝试通过exchange.IO发送Post-Only订单。路径: {api_path}, 参数: {params_str}")
raw_response = exchange.IO("api", "POST", api_path, params_str)
Log(f"原始exchange.IO响应: {raw_response}")
actual_order_id = None
response = None
if raw_response is None or raw_response == "<nil>" or raw_response == "":
Log(f"错误: exchange.IO返回了空值或无效响应 ('{raw_response}')。下单失败。")
return None
if isinstance(raw_response, dict):
response = raw_response
Log("信息: exchange.IO直接返回了字典对象,已直接使用。")
elif isinstance(raw_response, str):
try:
response = json.loads(raw_response)
except Exception as e:
Log(f"错误: 解析exchange.IO响应字符串失败: {raw_response}, 错误详情: {e}")
if str(raw_response).strip():
Log(f"提示: 响应无法解析为JSON,但看起来像一个订单ID字符串: '{raw_response}'. 尝试将其作为订单ID处理。")
actual_order_id = str(raw_response).strip()
else:
return None
else:
Log(f"错误: exchange.IO返回了无法处理的类型: {type(raw_response)}。内容: {raw_response}")
return None
if not actual_order_id:
if response and isinstance(response, dict) and response.get("id"):
actual_order_id = response.get("id")
Log(f"信息: Post-Only订单提交成功。实际订单ID: {actual_order_id}, 状态: {response.get('status')}")
if response.get('status') == 'cancelled':
Log(f"警告: 订单{actual_order_id}因Post-Only规则被立即取消。")
return None
elif response and isinstance(response, dict) and response.get("message"):
Log(f"错误: 下单失败。标签: {response.get('label')}, 消息: {response.get('message')}")
return None
elif response:
Log(f"错误: 下单失败或无法解析响应。未知的响应格式: {response}")
return None
if not actual_order_id:
Log("错误: 未获取到实际订单ID。")
return None
fmz_order_id = f"{contract},{str(actual_order_id)}"
Log(f"信息: 构造的FMZ订单ID: {fmz_order_id}")
pending_orders[fmz_order_id] = {
'time': time.time(),
'type': direction,
'price': price,
'amount': amount,
'is_close': is_close
}
operation_type = "平仓" if is_close else "开仓"
direction_text = "买入/做多" if direction == "buy" else "卖出/做空"
Log(f"Post-Only下单成功 - {operation_type} {direction_text} 价格: {price} 数量: {amount} 订单ID: {fmz_order_id}")
if not is_close:
position_type = "long" if direction == "buy" else "short"
entry_prices[position_type] = price
Log(f"记录{position_type}持仓入场价格: {price}")
return fmz_order_id
except Exception as e:
Log(f"Post-Only下单异常: {e}")
Log(f"详细错误: {traceback.format_exc()}")
Log("严格模式:只使用Post-Only订单,不降级为普通限价单")
return None
def check_and_cancel_pending_orders():
"""
检查并取消超过2秒未成交的挂单
"""
current_time = time.time()
orders_to_cancel = []
for order_id, order_info in list(pending_orders.items()):
if current_time - order_info['time'] > 2: # 超过2秒
orders_to_cancel.append((order_id, order_info))
for order_id, order_info in orders_to_cancel:
try:
details = get_contract_details()
if not details:
Log("错误: 无法获取合约详情,取消订单失败")
continue
parts = order_id.split(',')
if len(parts) != 2:
Log(f"错误: 无效的订单ID格式: {order_id}")
continue
contract = parts[0]
actual_order_id = parts[1]
settle = details['settle']
api_path = f"/api/v4/futures/{settle}/orders/{actual_order_id}"
Log(f"尝试通过exchange.IO取消订单。路径: {api_path}")
raw_response = exchange.IO("api", "DELETE", api_path, "")
Log(f"原始exchange.IO取消订单响应: {raw_response}")
if raw_response is None or raw_response == "<nil>" or raw_response == "":
Log(f"错误: 取消订单返回了空值或无效响应 ('{raw_response}')。")
continue
if order_id in pending_orders:
del pending_orders[order_id]
operation_type = "平仓" if order_info.get('is_close', False) else "开仓"
direction_text = "买入/做多" if order_info['type'] == "buy" else "卖出/做空"
Log(f"取消超时订单 - {operation_type} {direction_text} 价格: {order_info['price']} 订单ID: {order_id} 结果: 成功")
except Exception as e:
Log(f"取消订单异常: {e}")
Log(f"详细错误: {traceback.format_exc()}")
def update_pending_orders():
"""
更新挂单状态,移除已成交订单
"""
try:
details = get_contract_details()
if not details:
Log("错误: 无法获取合约详情,更新挂单状态失败")
return
settle = details['settle']
api_path = f"/api/v4/futures/{settle}/orders"
Log(f"尝试通过exchange.IO获取未完成订单。路径: {api_path}")
raw_response = exchange.IO("api", "GET", api_path, "status=open")
if raw_response is None or raw_response == "<nil>" or raw_response == "":
Log(f"信息: 没有未完成订单,清空pending_orders")
pending_orders.clear()
return
if isinstance(raw_response, str):
try:
response = json.loads(raw_response)
except Exception as e:
Log(f"错误: 解析未完成订单响应失败: {e}")
return
elif isinstance(raw_response, list):
response = raw_response
else:
Log(f"错误: 未完成订单响应格式不正确: {type(raw_response)}")
return
current_order_ids = []
for order in response:
if isinstance(order, dict) and 'id' in order:
contract = details['contract']
actual_order_id = order['id']
fmz_order_id = f"{contract},{actual_order_id}"
current_order_ids.append(fmz_order_id)
for order_id in list(pending_orders.keys()):
if order_id not in current_order_ids:
del pending_orders[order_id]
except Exception as e:
Log(f"更新挂单状态异常: {e}")
Log(f"详细错误: {traceback.format_exc()}")
def update_status_bar():
"""
更新状态栏信息,包含完善的错误处理
"""
global is_paused_after_stop_loss, g_stop_loss_cooldown_end_time
balance = "获取失败"
position_info = "无持仓"
error_info = ""
position = None
try:
try:
account = exchange.GetAccount()
if account and 'Balance' in account and account['Balance'] is not None:
balance = _N(account['Balance'], 2)
else:
error_info += "账户余额获取失败; "
except Exception as e:
error_info += f"账户API异常: {str(e)}; "
try:
position = exchange.GetPosition()
if position and len(position) > 0 and position[0]:
pos_type = "多头" if position[0]['Type'] == PD_LONG else "空头"
pos_amount = position[0].get('Amount', 0)
pos_price = position[0].get('Price', 0)
if pos_price is not None and pos_amount is not None:
position_info = f"{pos_type} 数量:{pos_amount} 均价:{_N(pos_price, price_precision)}"
else:
position_info = f"{pos_type} 数据不完整"
else:
position_info = "无持仓"
except Exception as e:
error_info += f"持仓API异常: {str(e)}; "
position_info = "获取失败"
upper_channel = _N(AXMNLQXHRBU, price_precision) if AXMNLQXHRBU is not None else "未初始化"
lower_channel = _N(AQDVNLQXHRBU, price_precision) if AQDVNLQXHRBU is not None else "未初始化"
signal_status = "无活跃信号"
if active_signal:
elapsed_time = time.time() - signal_start_time
remaining_time = max(0, signal_duration - elapsed_time)
signal_status = f"{active_signal} (剩余时间: {_N(remaining_time, 1)}秒)"
stop_loss_info = "无活跃止损订单"
stop_loss_threshold = "未设置"
current_position_type = None
current_entry_price = None
if position and len(position) > 0 and position[0]:
current_position_type = "long" if position[0]['Type'] == PD_LONG else "short"
current_entry_price = entry_prices.get(current_position_type)
if current_entry_price is None:
current_entry_price = position[0]['Price']
entry_prices[current_position_type] = current_entry_price
stop_loss_threshold = calculate_stop_loss_threshold(current_position_type, current_entry_price)
if stop_loss_threshold is not None:
stop_loss_threshold = _N(stop_loss_threshold, price_precision)
if stop_loss_orders:
stop_loss_prices = []
for order_id, order_info in stop_loss_orders.items():
stop_loss_prices.append(_N(order_info['price'], price_precision))
if stop_loss_prices:
stop_loss_info = f"止损订单: {len(stop_loss_orders)}, 价格: {', '.join(map(str, stop_loss_prices))}"
strategy_status = "正常运行"
if is_paused_after_stop_loss:
current_time = time.time()
if current_time < g_stop_loss_cooldown_end_time:
remaining_minutes = (g_stop_loss_cooldown_end_time - current_time) / 60
strategy_status = f"止损后冷却暂停中 (剩余: {_N(remaining_minutes, 1)}分钟) | 止损订单保持活跃"
else:
is_paused_after_stop_loss = False
g_stop_loss_cooldown_end_time = 0
strategy_status = "暂停已结束,恢复正常运行"
error_table = ""
if error_info:
error_table = "\n错误信息: " + error_info
LogStatus(
"策略运行中 - 最后更新时间:", _D(), "\n",
"账户余额:", balance, "USDT\n",
"持仓信息:", position_info, "\n",
"上轨:", upper_channel, "\n",
"下轨:", lower_channel, "\n",
"挂单数量:", len(pending_orders), "\n",
"止损阈值:", stop_loss_threshold, "\n",
"止损信息:", stop_loss_info, "\n",
"策略状态:", strategy_status, "\n",
"活跃信号:", signal_status, "\n",
error_table
)
except Exception as e:
try:
LogStatus(f"状态栏更新异常: {e}\n详细错误: {traceback.format_exc()}")
except:
Log("严重错误: 状态栏完全无法更新")
def AQBONQXHRBU():
"""
主要策略逻辑
"""
global AXMNIYHRBU, AXMNLQXHRBU, AQDVNLQXHRBU, ABAVGBA, AQDVNQXHRBU
global active_signal, signal_start_time
global is_paused_after_stop_loss, g_stop_loss_cooldown_end_time
try:
current_time = time.time()
if is_paused_after_stop_loss:
if current_time >= g_stop_loss_cooldown_end_time:
is_paused_after_stop_loss = False
g_stop_loss_cooldown_end_time = 0
Log("止损后冷却期已结束,策略恢复所有交易活动。")
else:
remaining_minutes = (g_stop_loss_cooldown_end_time - current_time) / 60
Log(f"策略处于止损后冷却暂停状态,剩余时间: {_N(remaining_minutes, 1)}分钟。只执行止损订单管理。")
update_pending_orders()
check_and_cancel_pending_orders()
check_and_handle_stop_loss_orders()
AXBONQXHRBU = exchange.GetRecords()
if AXBONQXHRBU is None or len(AXBONQXHRBU) < AXXAIMBRBU + 1:
Log("K线数据不足,等待更多数据...")
Sleep(1000)
return
AMNMVGBA = AXBONQXHRBU[-1]
AMXMVGBA = AMNMVGBA["Time"]
if AXMNIYHRBU != AMXMVGBA:
Log("检测到新K线,更新通道上下轨...")
trValues = AQTONQXHRBU(AXBONQXHRBU)
ADMHMVGB = AQNONQXHRBU(trValues, AXXAIMBRBU)
AMHMVGBA = ADMHMVGB * AXXAIMHRBU
ADHMVGBC = AXBONQXHRBU[-1]["Close"]
AXMNLQXHRBU = ADHMVGBC + AMHMVGBA
AQDVNLQXHRBU = ADHMVGBC - AMHMVGBA
AXMNIYHRBU = AMXMVGBA
Log(f"通道更新 - 上轨: {_N(AXMNLQXHRBU, price_precision)} 下轨: {_N(AQDVNLQXHRBU, price_precision)}")
ABAGBA = _C(exchange.GetTicker)
if ABAGBA is None:
Log("获取行情失败,跳过本次循环")
return
ABBAVGBA = exchange.GetPosition()
if ABBAVGBA and len(ABBAVGBA) > 0 and ABBAVGBA[0] is not None:
position_type = "long" if ABBAVGBA[0]["Type"] == PD_LONG else "short"
position_amount = ABBAVGBA[0]["Amount"]
position_price = ABBAVGBA[0]["Price"]
if position_type not in entry_prices or entry_prices[position_type] is None:
entry_prices[position_type] = position_price
Log(f"记录{position_type}持仓入场价格: {position_price}")
if check_stop_loss_condition(position_type, entry_prices[position_type], ABAGBA.Last):
Log(f"触发{position_type}持仓止损条件,入场价: {entry_prices[position_type]}, 当前价: {ABAGBA.Last}")
inventory = position_amount if position_type == "long" else -position_amount
if not stop_loss_orders:
execute_stop_loss(position_type, position_amount, ABAGBA.Last, inventory)
global is_stop_loss_order_pending
if is_paused_after_stop_loss or is_stop_loss_order_pending:
if is_paused_after_stop_loss:
Log("策略处于冷却暂停状态,跳过新的交易信号处理和开仓/平仓操作。")
elif is_stop_loss_order_pending:
Log("止损订单正在处理中,跳过新的交易信号处理和开仓/平仓操作。")
return
inventory = 0
if ABBAVGBA and len(ABBAVGBA) > 0 and ABBAVGBA[0] is not None:
inventory = ABBAVGBA[0]["Amount"] if ABBAVGBA[0]["Type"] == PD_LONG else -ABBAVGBA[0]["Amount"]
mid_price = (ABAGBA.Buy + ABAGBA.Sell) / 2
Log(f"当前价格: {_N(ABAGBA.Last, price_precision)} 上轨: {_N(AXMNLQXHRBU, price_precision)} 下轨: {_N(AQDVNLQXHRBU, price_precision)} 库存: {inventory}")
current_time = time.time()
if active_signal and current_time - signal_start_time > signal_duration:
Log(f"信号 {active_signal} 已超时 (持续时间: {current_time - signal_start_time:.2f}s > {signal_duration}s),取消信号")
active_signal = None
signal_start_time = 0
if pending_orders:
return
details = get_contract_details()
if not details:
Log("错误: 无法获取合约详情,跳过交易信号处理")
return
AQDVNQXHRBU = float(details["contract_value_base"])
if active_signal:
Log(f"处理活跃信号: {active_signal}")
if AQDVNQXHRBU == 0:
Log("警告:合约面值为0,无法计算交易数量")
return
ABAVGBA = _N(AXXBZMBRBU * AXXAIYHRBU / (ABAGBA.Last * AQDVNQXHRBU), 0)
if ABAVGBA < 1:
ABAVGBA = 1
if active_signal == "long":
if ABBAVGBA is None or len(ABBAVGBA) == 0 or ABBAVGBA[0] is None:
Log(f"根据活跃信号做多,价格: {_N(ABAGBA.Last, price_precision)}")
optimal_price = calculate_optimal_price(mid_price, inventory, "buy")
tick_size = Decimal("1e-" + str(price_precision))
buffer_amount = maker_buffer_ticks * tick_size
buffered_price = Decimal(str(optimal_price)) - buffer_amount
limit_price_rounded = (buffered_price / tick_size).to_integral_value(rounding=ROUND_DOWN) * tick_size
limit_price = float(limit_price_rounded)
Log(f"价格计算详情 - 操作:开多 中间价:{mid_price} 最优价:{optimal_price} 缓冲后:{float(buffered_price)} 最终价格:{limit_price}")
place_post_only_order("buy", limit_price, ABAVGBA, is_close=False)
elif ABBAVGBA[0]["Type"] == PD_SHORT:
Log("空转多信号,平空后开多")
open_long_price = calculate_optimal_price(mid_price, 0, "buy")
has_position = check_actual_position("short")
if has_position:
tick_size = Decimal("1e-" + str(price_precision))
buffer_amount = close_maker_buffer_ticks * tick_size
buffered_price = Decimal(str(open_long_price)) - buffer_amount
close_price_rounded = (buffered_price / tick_size).to_integral_value(rounding=ROUND_DOWN) * tick_size
close_price = float(close_price_rounded)
Log(f"价格计算详情 - 操作:平空 中间价:{mid_price} 最优价:{open_long_price} 缓冲后:{float(buffered_price)} 最终价格:{close_price}")
order_id = place_post_only_order("buy", close_price, ABBAVGBA[0]["Amount"], is_close=True)
if order_id:
Sleep(500)
buffer_amount = maker_buffer_ticks * tick_size
buffered_open_price = Decimal(str(open_long_price)) - buffer_amount
open_price_rounded = (buffered_open_price / tick_size).to_integral_value(rounding=ROUND_DOWN) * tick_size
open_price = float(open_price_rounded)
Log(f"价格计算详情 - 操作:开多 中间价:{mid_price} 最优价:{open_long_price} 缓冲后:{float(buffered_open_price)} 最终价格:{open_price}")
place_post_only_order("buy", open_price, ABAVGBA, is_close=False)
else:
Log("交易所查询显示无空仓可平,直接开多")
tick_size = Decimal("1e-" + str(price_precision))
buffer_amount = maker_buffer_ticks * tick_size
buffered_open_price = Decimal(str(open_long_price)) - buffer_amount
open_price_rounded = (buffered_open_price / tick_size).to_integral_value(rounding=ROUND_DOWN) * tick_size
open_price = float(open_price_rounded)
Log(f"价格计算详情 - 操作:开多 中间价:{mid_price} 最优价:{open_long_price} 缓冲后:{float(buffered_open_price)} 最终价格:{open_price}")
place_post_only_order("buy", open_price, ABAVGBA, is_close=False)
else:
Log("已有多仓,忽略做多信号")
elif active_signal == "short":
if ABBAVGBA is None or len(ABBAVGBA) == 0 or ABBAVGBA[0] is None:
Log(f"根据活跃信号做空,价格: {_N(ABAGBA.Last, price_precision)}")
optimal_price = calculate_optimal_price(mid_price, inventory, "sell")
tick_size = Decimal("1e-" + str(price_precision))
buffer_amount = maker_buffer_ticks * tick_size
buffered_price = Decimal(str(optimal_price)) + buffer_amount
limit_price_rounded = (buffered_price / tick_size).to_integral_value(rounding=ROUND_HALF_UP) * tick_size
limit_price = float(limit_price_rounded)
Log(f"价格计算详情 - 操作:开空 中间价:{mid_price} 最优价:{optimal_price} 缓冲后:{float(buffered_price)} 最终价格:{limit_price}")
place_post_only_order("sell", limit_price, ABAVGBA, is_close=False)
elif ABBAVGBA[0]["Type"] == PD_LONG:
Log("多转空信号,平多后开空")
open_short_price = calculate_optimal_price(mid_price, 0, "sell")
has_position = check_actual_position("long")
if has_position:
tick_size = Decimal("1e-" + str(price_precision))
buffer_amount = close_maker_buffer_ticks * tick_size
buffered_price = Decimal(str(open_short_price)) + buffer_amount
close_price_rounded = (buffered_price / tick_size).to_integral_value(rounding=ROUND_HALF_UP) * tick_size
close_price = float(close_price_rounded)
Log(f"价格计算详情 - 操作:平多 中间价:{mid_price} 最优价:{open_short_price} 缓冲后:{float(buffered_price)} 最终价格:{close_price}")
order_id = place_post_only_order("sell", close_price, ABBAVGBA[0]["Amount"], is_close=True)
if order_id:
Sleep(500)
buffer_amount = maker_buffer_ticks * tick_size
buffered_open_price = Decimal(str(open_short_price)) + buffer_amount
open_price_rounded = (buffered_open_price / tick_size).to_integral_value(rounding=ROUND_HALF_UP) * tick_size
open_price = float(open_price_rounded)
Log(f"价格计算详情 - 操作:开空 中间价:{mid_price} 最优价:{open_short_price} 缓冲后:{float(buffered_open_price)} 最终价格:{open_price}")
place_post_only_order("sell", open_price, ABAVGBA, is_close=False)
else:
Log("交易所查询显示无多仓可平,直接开空")
tick_size = Decimal("1e-" + str(price_precision))
buffer_amount = maker_buffer_ticks * tick_size
buffered_open_price = Decimal(str(open_short_price)) + buffer_amount
open_price_rounded = (buffered_open_price / tick_size).to_integral_value(rounding=ROUND_HALF_UP) * tick_size
open_price = float(open_price_rounded)
Log(f"价格计算详情 - 操作:开空 中间价:{mid_price} 最优价:{open_short_price} 缓冲后:{float(buffered_open_price)} 最终价格:{open_price}")
place_post_only_order("sell", open_price, ABAVGBA, is_close=False)
else:
Log("已有空仓,忽略做空信号")
return
if ABAGBA.Last >= AXMNLQXHRBU:
Log(f"价格突破上轨,生成做空信号。价格: {_N(ABAGBA.Last, price_precision)}")
active_signal = "short"
signal_start_time = current_time
return
if ABAGBA.Last <= AQDVNLQXHRBU:
Log(f"价格突破下轨,生成做多信号。价格: {_N(ABAGBA.Last, price_precision)}")
active_signal = "long"
signal_start_time = current_time
return
except Exception as e:
Log(f"策略执行异常: {e}")
Log(f"详细错误: {traceback.format_exc()}")
def main():
"""
策略入口函数
"""
global AQDVNQXHRBU, allow_new_positions
allow_new_positions = True
exchange.SetContractType('swap')
exchange.SetMarginLevel(AXXAIYHRBU)
check_and_set_position_mode()
SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused|Unknown")
ADMVGBCD = exchange.GetAccount()
if ADMVGBCD is None:
Log("警告:无法获取账户信息")
ADVGBCDE = 0
else:
ADVGBCDE = ADMVGBCD['Balance']
Log(f"初始金额: {_N(ADVGBCDE, 2)}")
details = get_contract_details()
if details:
AQDVNQXHRBU = float(details['contract_value_base'])
Log(f"合约面值: {AQDVNQXHRBU}")
else:
Log("警告:无法获取合约详情,使用默认值")
AQDVNQXHRBU = 1
Log("策略初始化完成,开始主循环...")
Log("使用Avellaneda-Stoikov最优报价模型,2秒未成交则撤单重挂")
Log("使用size正负值控制方向,确保Gate.io合约API兼容性")
Log("百分百Post-Only订单,确保只挂单不吃单")
Log(f"信号持久化功能已启用,信号持续时间: {signal_duration}秒")
Log(f"百分比止损功能已启用,止损百分比: {STOP_LOSS_PERCENT}%")
Log(f"止损后停止开新仓功能已启用")
while True:
try:
AQBONQXHRBU()
Sleep(1000)
update_status_bar()
except Exception as e:
Log(f"主循环异常: {e}")
Log(f"详细错误: {traceback.format_exc()}")
Sleep(5000)
if __name__ == '__main__':
main()
全部留言
SEA
希望大哥 大佬给出宝贵的建议!
2025-07-17 20:48:53