ATR反向策略


创建日期: 2025-06-17 01:43:04 最后修改: 2025-09-07 06:16:27
复制: 0 点击次数: 433
2
关注
35
关注者
策略源码
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()

全部留言
avatar of SEA
SEA
希望大哥 大佬给出宝贵的建议!
2025-07-17 20:48:53