|
|
@@ -1288,9 +1288,6 @@ def open_position(context, security, target_hands, direction, single_hand_margin
|
|
|
f"保证金: {margin_change:.0f}, 资金变化: {cash_change:.0f}, 原因: {reason}, "
|
|
|
f"穿越均线: {crossed_ma_str}")
|
|
|
|
|
|
- # log.debug(f"开仓后检查并补足保证金占用,使其满足最小要求")
|
|
|
- # verify_position_margin_requirement(context, security)
|
|
|
-
|
|
|
return True
|
|
|
|
|
|
except Exception as e:
|
|
|
@@ -1298,145 +1295,6 @@ def open_position(context, security, target_hands, direction, single_hand_margin
|
|
|
|
|
|
return False
|
|
|
|
|
|
-def verify_position_margin_requirement(context, security):
|
|
|
- """开仓后检查并补足保证金占用,使其满足最小要求"""
|
|
|
- try:
|
|
|
- min_margin = getattr(g, 'max_margin_per_position', 0)
|
|
|
- trade_info = g.trade_history.get(security)
|
|
|
-
|
|
|
- if min_margin <= 0 or not trade_info:
|
|
|
- return True
|
|
|
-
|
|
|
- actual_margin = trade_info.get('actual_margin', 0)
|
|
|
- actual_hands = trade_info.get('actual_hands', 0)
|
|
|
-
|
|
|
- if actual_hands <= 0:
|
|
|
- log.warning(f"保证金校验跳过: {security} 无有效持仓信息")
|
|
|
- return False
|
|
|
-
|
|
|
- if actual_margin >= min_margin:
|
|
|
- log.debug(f"{security} 实际保证金 {actual_margin:.0f} 已满足要求 {min_margin:.0f}")
|
|
|
- return True
|
|
|
-
|
|
|
- underlying_symbol = security.split('.')[0][:-4]
|
|
|
- direction = trade_info.get('direction')
|
|
|
- multiplier = get_multiplier(underlying_symbol)
|
|
|
-
|
|
|
- current_data = get_current_data()
|
|
|
- entry_price = trade_info.get('entry_price')
|
|
|
-
|
|
|
- def _safe_price(data, symbol):
|
|
|
- try:
|
|
|
- return data[symbol].last_price
|
|
|
- except Exception:
|
|
|
- return None
|
|
|
-
|
|
|
- market_price = _safe_price(current_data, security)
|
|
|
- price_for_rate = entry_price if entry_price and entry_price > 0 else market_price
|
|
|
-
|
|
|
- if not price_for_rate or price_for_rate <= 0 or multiplier <= 0:
|
|
|
- log.warning(f"保证金校验失败: {security} 缺少价格或乘数数据")
|
|
|
- return False
|
|
|
-
|
|
|
- contract_value = price_for_rate * multiplier * actual_hands
|
|
|
- if contract_value <= 0:
|
|
|
- log.warning(f"保证金校验失败: {security} 名义价值无效")
|
|
|
- return False
|
|
|
-
|
|
|
- actual_margin_rate = actual_margin / contract_value
|
|
|
- if actual_margin_rate <= 0:
|
|
|
- log.warning(f"保证金校验失败: {security} 无法计算保证金比例")
|
|
|
- return False
|
|
|
-
|
|
|
- # 更新对应方向的保证金率配置
|
|
|
- if underlying_symbol in g.futures_config and direction:
|
|
|
- margin_cfg = g.futures_config[underlying_symbol].setdefault('margin_rate', {})
|
|
|
- prev_rate = margin_cfg.get(direction)
|
|
|
- margin_cfg[direction] = actual_margin_rate
|
|
|
- prev_rate_display = f"{prev_rate:.4f}" if prev_rate else "0.0000"
|
|
|
- log.info(f"{underlying_symbol} {direction} 保证金率校准: {prev_rate_display} -> {actual_margin_rate:.4f}")
|
|
|
-
|
|
|
- max_iterations = 3
|
|
|
- while trade_info['actual_margin'] < min_margin and max_iterations > 0:
|
|
|
- max_iterations -= 1
|
|
|
- market_data = get_current_data()
|
|
|
- latest_price = _safe_price(market_data, security) or price_for_rate
|
|
|
-
|
|
|
- if not latest_price or latest_price <= 0:
|
|
|
- log.warning(f"保证金补仓失败: {security} 缺少最新价格")
|
|
|
- break
|
|
|
-
|
|
|
- single_hand_margin = latest_price * multiplier * actual_margin_rate
|
|
|
- if single_hand_margin <= 0:
|
|
|
- log.warning(f"保证金补仓失败: {security} 无法计算单手保证金")
|
|
|
- break
|
|
|
-
|
|
|
- ideal_total_hands = math.ceil(min_margin / single_hand_margin)
|
|
|
- if ideal_total_hands * single_hand_margin > min_margin:
|
|
|
- ideal_total_hands = max(int(min_margin / single_hand_margin), trade_info['actual_hands'])
|
|
|
-
|
|
|
- if ideal_total_hands <= trade_info['actual_hands']:
|
|
|
- log.info(f"{security} 无法进一步增仓,单手保证金 {single_hand_margin:.0f} 限制")
|
|
|
- break
|
|
|
-
|
|
|
- available_cash = context.portfolio.available_cash * g.usage_percentage
|
|
|
- if available_cash <= 0:
|
|
|
- log.warning(f"{security} 可用资金不足,无法补仓")
|
|
|
- break
|
|
|
-
|
|
|
- max_additional_by_cash = int(available_cash / single_hand_margin)
|
|
|
- if max_additional_by_cash <= 0:
|
|
|
- log.warning(f"{security} 可用资金不足以增加1手")
|
|
|
- break
|
|
|
-
|
|
|
- target_hands = min(ideal_total_hands, trade_info['actual_hands'] + max_additional_by_cash)
|
|
|
- additional_hands = target_hands - trade_info['actual_hands']
|
|
|
-
|
|
|
- if additional_hands <= 0:
|
|
|
- log.info(f"{security} 目标手数未增加,跳过补仓")
|
|
|
- break
|
|
|
-
|
|
|
- cash_before = context.portfolio.available_cash
|
|
|
- order = order_target(security, target_hands, side=direction)
|
|
|
-
|
|
|
- if not order or order.filled <= 0:
|
|
|
- log.warning(f"{security} 保证金补仓订单未成交")
|
|
|
- break
|
|
|
-
|
|
|
- cash_after = context.portfolio.available_cash
|
|
|
- additional_margin_used = max(0, cash_before - cash_after)
|
|
|
- if additional_margin_used <= 0:
|
|
|
- additional_margin_used = order.filled * single_hand_margin
|
|
|
-
|
|
|
- trade_info['actual_hands'] += order.filled
|
|
|
- trade_info['target_hands'] = target_hands
|
|
|
- trade_info['actual_margin'] += additional_margin_used
|
|
|
-
|
|
|
- g.today_trades.append({
|
|
|
- 'security': security,
|
|
|
- 'underlying_symbol': underlying_symbol,
|
|
|
- 'direction': direction,
|
|
|
- 'order_amount': order.filled,
|
|
|
- 'order_price': order.avg_cost if order.avg_cost else order.price,
|
|
|
- 'cash_change': additional_margin_used,
|
|
|
- 'margin_change': additional_margin_used,
|
|
|
- 'time': context.current_dt,
|
|
|
- 'reason': 'margin_adjustment'
|
|
|
- })
|
|
|
-
|
|
|
- log.info(f"{security} 保证金补仓成功: +{order.filled}手, 总手数 {trade_info['actual_hands']}手, "
|
|
|
- f"总保证金 {trade_info['actual_margin']:.0f}/{min_margin:.0f}")
|
|
|
-
|
|
|
- if trade_info['actual_margin'] < min_margin:
|
|
|
- log.warning(f"{security} 补仓后仍未达到保证金要求 {trade_info['actual_margin']:.0f}/{min_margin:.0f}")
|
|
|
- return False
|
|
|
-
|
|
|
- return True
|
|
|
-
|
|
|
- except Exception as e:
|
|
|
- log.warning(f"保证金校验异常 {security}: {str(e)}")
|
|
|
- return False
|
|
|
-
|
|
|
def close_position(context, security, direction):
|
|
|
"""平仓"""
|
|
|
try:
|