Add personal license agreement and rename product section to tradable symbols.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+127
-122
@@ -1,122 +1,127 @@
|
||||
"""国内期货合约乘数与参考保证金比例(用于估算保证金与风险)。"""
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
DEFAULT_SPEC = {"mult": 10, "margin_rate": 0.10, "tick_size": 1.0}
|
||||
|
||||
# 参考交易所常见规格(乘数 + 保证金比例 + 最小变动价位)
|
||||
_SPEC_BY_THS: dict[str, dict] = {
|
||||
"ag": {"mult": 15, "margin_rate": 0.14, "tick_size": 1.0},
|
||||
"au": {"mult": 1000, "margin_rate": 0.10, "tick_size": 0.02},
|
||||
"cu": {"mult": 5, "margin_rate": 0.10, "tick_size": 10.0},
|
||||
"al": {"mult": 5, "margin_rate": 0.10},
|
||||
"zn": {"mult": 5, "margin_rate": 0.10},
|
||||
"pb": {"mult": 5, "margin_rate": 0.10},
|
||||
"ni": {"mult": 1, "margin_rate": 0.12},
|
||||
"sn": {"mult": 1, "margin_rate": 0.12},
|
||||
"rb": {"mult": 10, "margin_rate": 0.09},
|
||||
"hc": {"mult": 10, "margin_rate": 0.09},
|
||||
"ss": {"mult": 5, "margin_rate": 0.11},
|
||||
"sc": {"mult": 1000, "margin_rate": 0.11},
|
||||
"fu": {"mult": 10, "margin_rate": 0.11},
|
||||
"bu": {"mult": 10, "margin_rate": 0.11},
|
||||
"ru": {"mult": 10, "margin_rate": 0.11},
|
||||
"sp": {"mult": 10, "margin_rate": 0.10},
|
||||
"i": {"mult": 100, "margin_rate": 0.11},
|
||||
"j": {"mult": 100, "margin_rate": 0.12},
|
||||
"jm": {"mult": 60, "margin_rate": 0.12},
|
||||
"m": {"mult": 10, "margin_rate": 0.08},
|
||||
"y": {"mult": 10, "margin_rate": 0.08},
|
||||
"p": {"mult": 10, "margin_rate": 0.09},
|
||||
"c": {"mult": 10, "margin_rate": 0.08},
|
||||
"cs": {"mult": 10, "margin_rate": 0.08},
|
||||
"jd": {"mult": 10, "margin_rate": 0.09},
|
||||
"lh": {"mult": 16, "margin_rate": 0.12},
|
||||
"l": {"mult": 5, "margin_rate": 0.09},
|
||||
"pp": {"mult": 5, "margin_rate": 0.09},
|
||||
"v": {"mult": 5, "margin_rate": 0.09},
|
||||
"eg": {"mult": 10, "margin_rate": 0.09},
|
||||
"eb": {"mult": 5, "margin_rate": 0.10},
|
||||
"pg": {"mult": 20, "margin_rate": 0.10},
|
||||
"RM": {"mult": 10, "margin_rate": 0.08},
|
||||
"OI": {"mult": 10, "margin_rate": 0.08},
|
||||
"SR": {"mult": 10, "margin_rate": 0.08},
|
||||
"CF": {"mult": 5, "margin_rate": 0.08},
|
||||
"MA": {"mult": 10, "margin_rate": 0.09},
|
||||
"TA": {"mult": 5, "margin_rate": 0.09},
|
||||
"FG": {"mult": 20, "margin_rate": 0.10},
|
||||
"SA": {"mult": 20, "margin_rate": 0.10},
|
||||
"UR": {"mult": 20, "margin_rate": 0.10},
|
||||
"SF": {"mult": 5, "margin_rate": 0.10},
|
||||
"SM": {"mult": 5, "margin_rate": 0.10},
|
||||
"AP": {"mult": 10, "margin_rate": 0.10},
|
||||
"CJ": {"mult": 5, "margin_rate": 0.10},
|
||||
"PK": {"mult": 5, "margin_rate": 0.10},
|
||||
"IF": {"mult": 300, "margin_rate": 0.12, "tick_size": 0.2},
|
||||
"IH": {"mult": 300, "margin_rate": 0.12, "tick_size": 0.2},
|
||||
"IC": {"mult": 200, "margin_rate": 0.12, "tick_size": 0.2},
|
||||
"IM": {"mult": 200, "margin_rate": 0.12, "tick_size": 0.2},
|
||||
}
|
||||
|
||||
_TICK_OVERRIDES: dict[str, float] = {
|
||||
"sc": 0.1, "TA": 2.0, "CF": 5.0, "SF": 2.0, "SM": 2.0,
|
||||
}
|
||||
|
||||
|
||||
def get_contract_spec(ths_code: str) -> dict:
|
||||
code = (ths_code or "").strip()
|
||||
m = re.match(r"^([A-Za-z]+)", code)
|
||||
if not m:
|
||||
return dict(DEFAULT_SPEC)
|
||||
letters = m.group(1)
|
||||
spec = _SPEC_BY_THS.get(letters) or _SPEC_BY_THS.get(letters.upper()) or _SPEC_BY_THS.get(letters.lower())
|
||||
if spec:
|
||||
tick = spec.get("tick_size")
|
||||
if tick is None:
|
||||
tick = _TICK_OVERRIDES.get(letters) or _TICK_OVERRIDES.get(letters.upper()) or 1.0
|
||||
return {"mult": spec["mult"], "margin_rate": spec["margin_rate"], "tick_size": float(tick)}
|
||||
return dict(DEFAULT_SPEC)
|
||||
|
||||
|
||||
def calc_position_metrics(
|
||||
direction: str,
|
||||
entry: float,
|
||||
stop_loss: float,
|
||||
take_profit: float,
|
||||
lots: float,
|
||||
mark_price: Optional[float],
|
||||
capital: float,
|
||||
ths_code: str,
|
||||
) -> dict:
|
||||
spec = get_contract_spec(ths_code)
|
||||
mult = spec["mult"]
|
||||
margin_rate = spec["margin_rate"]
|
||||
lots = lots or 1.0
|
||||
margin = entry * mult * lots * margin_rate
|
||||
|
||||
if direction == "long":
|
||||
risk_amt = max(0.0, (entry - stop_loss) * mult * lots)
|
||||
reward = max(0.0, (take_profit - entry) * mult * lots)
|
||||
float_pnl = (mark_price - entry) * mult * lots if mark_price is not None else None
|
||||
else:
|
||||
risk_amt = max(0.0, (stop_loss - entry) * mult * lots)
|
||||
reward = max(0.0, (entry - take_profit) * mult * lots)
|
||||
float_pnl = (entry - mark_price) * mult * lots if mark_price is not None else None
|
||||
|
||||
risk_pct = (risk_amt / capital * 100) if capital > 0 else 0.0
|
||||
pos_pct = (margin / capital * 100) if capital > 0 else 0.0
|
||||
rr = (reward / risk_amt) if risk_amt > 0 else None
|
||||
float_pct = (float_pnl / margin * 100) if margin > 0 and float_pnl is not None else None
|
||||
|
||||
return {
|
||||
"mult": mult,
|
||||
"margin_rate": margin_rate,
|
||||
"margin": round(margin, 2),
|
||||
"risk_amount": round(risk_amt, 2),
|
||||
"risk_pct": round(risk_pct, 2),
|
||||
"position_pct": round(pos_pct, 2),
|
||||
"float_pnl": round(float_pnl, 2) if float_pnl is not None else None,
|
||||
"float_pct": round(float_pct, 2) if float_pct is not None else None,
|
||||
"reward_amount": round(reward, 2) if reward else None,
|
||||
"rr_ratio": round(rr, 2) if rr is not None else None,
|
||||
}
|
||||
# Copyright (c) 2025-2026 马建军. All rights reserved.
|
||||
# 专有软件 — 未经授权禁止复制、传播、转售。
|
||||
# 严禁用于:带单/代客理财、向他人推荐期货品种或买卖建议、融资配资等业务。
|
||||
# 详见 LICENSE.zh-CN.txt 与 docs/软件购买与使用协议.md
|
||||
|
||||
"""国内期货合约乘数与参考保证金比例(用于估算保证金与风险)。"""
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
DEFAULT_SPEC = {"mult": 10, "margin_rate": 0.10, "tick_size": 1.0}
|
||||
|
||||
# 参考交易所常见规格(乘数 + 保证金比例 + 最小变动价位)
|
||||
_SPEC_BY_THS: dict[str, dict] = {
|
||||
"ag": {"mult": 15, "margin_rate": 0.14, "tick_size": 1.0},
|
||||
"au": {"mult": 1000, "margin_rate": 0.10, "tick_size": 0.02},
|
||||
"cu": {"mult": 5, "margin_rate": 0.10, "tick_size": 10.0},
|
||||
"al": {"mult": 5, "margin_rate": 0.10},
|
||||
"zn": {"mult": 5, "margin_rate": 0.10},
|
||||
"pb": {"mult": 5, "margin_rate": 0.10},
|
||||
"ni": {"mult": 1, "margin_rate": 0.12},
|
||||
"sn": {"mult": 1, "margin_rate": 0.12},
|
||||
"rb": {"mult": 10, "margin_rate": 0.09},
|
||||
"hc": {"mult": 10, "margin_rate": 0.09},
|
||||
"ss": {"mult": 5, "margin_rate": 0.11},
|
||||
"sc": {"mult": 1000, "margin_rate": 0.11},
|
||||
"fu": {"mult": 10, "margin_rate": 0.11},
|
||||
"bu": {"mult": 10, "margin_rate": 0.11},
|
||||
"ru": {"mult": 10, "margin_rate": 0.11},
|
||||
"sp": {"mult": 10, "margin_rate": 0.10},
|
||||
"i": {"mult": 100, "margin_rate": 0.11},
|
||||
"j": {"mult": 100, "margin_rate": 0.12},
|
||||
"jm": {"mult": 60, "margin_rate": 0.12},
|
||||
"m": {"mult": 10, "margin_rate": 0.08},
|
||||
"y": {"mult": 10, "margin_rate": 0.08},
|
||||
"p": {"mult": 10, "margin_rate": 0.09},
|
||||
"c": {"mult": 10, "margin_rate": 0.08},
|
||||
"cs": {"mult": 10, "margin_rate": 0.08},
|
||||
"jd": {"mult": 10, "margin_rate": 0.09},
|
||||
"lh": {"mult": 16, "margin_rate": 0.12},
|
||||
"l": {"mult": 5, "margin_rate": 0.09},
|
||||
"pp": {"mult": 5, "margin_rate": 0.09},
|
||||
"v": {"mult": 5, "margin_rate": 0.09},
|
||||
"eg": {"mult": 10, "margin_rate": 0.09},
|
||||
"eb": {"mult": 5, "margin_rate": 0.10},
|
||||
"pg": {"mult": 20, "margin_rate": 0.10},
|
||||
"RM": {"mult": 10, "margin_rate": 0.08},
|
||||
"OI": {"mult": 10, "margin_rate": 0.08},
|
||||
"SR": {"mult": 10, "margin_rate": 0.08},
|
||||
"CF": {"mult": 5, "margin_rate": 0.08},
|
||||
"MA": {"mult": 10, "margin_rate": 0.09},
|
||||
"TA": {"mult": 5, "margin_rate": 0.09},
|
||||
"FG": {"mult": 20, "margin_rate": 0.10},
|
||||
"SA": {"mult": 20, "margin_rate": 0.10},
|
||||
"UR": {"mult": 20, "margin_rate": 0.10},
|
||||
"SF": {"mult": 5, "margin_rate": 0.10},
|
||||
"SM": {"mult": 5, "margin_rate": 0.10},
|
||||
"AP": {"mult": 10, "margin_rate": 0.10},
|
||||
"CJ": {"mult": 5, "margin_rate": 0.10},
|
||||
"PK": {"mult": 5, "margin_rate": 0.10},
|
||||
"IF": {"mult": 300, "margin_rate": 0.12, "tick_size": 0.2},
|
||||
"IH": {"mult": 300, "margin_rate": 0.12, "tick_size": 0.2},
|
||||
"IC": {"mult": 200, "margin_rate": 0.12, "tick_size": 0.2},
|
||||
"IM": {"mult": 200, "margin_rate": 0.12, "tick_size": 0.2},
|
||||
}
|
||||
|
||||
_TICK_OVERRIDES: dict[str, float] = {
|
||||
"sc": 0.1, "TA": 2.0, "CF": 5.0, "SF": 2.0, "SM": 2.0,
|
||||
}
|
||||
|
||||
|
||||
def get_contract_spec(ths_code: str) -> dict:
|
||||
code = (ths_code or "").strip()
|
||||
m = re.match(r"^([A-Za-z]+)", code)
|
||||
if not m:
|
||||
return dict(DEFAULT_SPEC)
|
||||
letters = m.group(1)
|
||||
spec = _SPEC_BY_THS.get(letters) or _SPEC_BY_THS.get(letters.upper()) or _SPEC_BY_THS.get(letters.lower())
|
||||
if spec:
|
||||
tick = spec.get("tick_size")
|
||||
if tick is None:
|
||||
tick = _TICK_OVERRIDES.get(letters) or _TICK_OVERRIDES.get(letters.upper()) or 1.0
|
||||
return {"mult": spec["mult"], "margin_rate": spec["margin_rate"], "tick_size": float(tick)}
|
||||
return dict(DEFAULT_SPEC)
|
||||
|
||||
|
||||
def calc_position_metrics(
|
||||
direction: str,
|
||||
entry: float,
|
||||
stop_loss: float,
|
||||
take_profit: float,
|
||||
lots: float,
|
||||
mark_price: Optional[float],
|
||||
capital: float,
|
||||
ths_code: str,
|
||||
) -> dict:
|
||||
spec = get_contract_spec(ths_code)
|
||||
mult = spec["mult"]
|
||||
margin_rate = spec["margin_rate"]
|
||||
lots = lots or 1.0
|
||||
margin = entry * mult * lots * margin_rate
|
||||
|
||||
if direction == "long":
|
||||
risk_amt = max(0.0, (entry - stop_loss) * mult * lots)
|
||||
reward = max(0.0, (take_profit - entry) * mult * lots)
|
||||
float_pnl = (mark_price - entry) * mult * lots if mark_price is not None else None
|
||||
else:
|
||||
risk_amt = max(0.0, (stop_loss - entry) * mult * lots)
|
||||
reward = max(0.0, (entry - take_profit) * mult * lots)
|
||||
float_pnl = (entry - mark_price) * mult * lots if mark_price is not None else None
|
||||
|
||||
risk_pct = (risk_amt / capital * 100) if capital > 0 else 0.0
|
||||
pos_pct = (margin / capital * 100) if capital > 0 else 0.0
|
||||
rr = (reward / risk_amt) if risk_amt > 0 else None
|
||||
float_pct = (float_pnl / margin * 100) if margin > 0 and float_pnl is not None else None
|
||||
|
||||
return {
|
||||
"mult": mult,
|
||||
"margin_rate": margin_rate,
|
||||
"margin": round(margin, 2),
|
||||
"risk_amount": round(risk_amt, 2),
|
||||
"risk_pct": round(risk_pct, 2),
|
||||
"position_pct": round(pos_pct, 2),
|
||||
"float_pnl": round(float_pnl, 2) if float_pnl is not None else None,
|
||||
"float_pct": round(float_pct, 2) if float_pct is not None else None,
|
||||
"reward_amount": round(reward, 2) if reward else None,
|
||||
"rr_ratio": round(rr, 2) if rr is not None else None,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user