Limit tradable products to four varieties for accounts at or below 100k.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+65
-1
@@ -18,6 +18,52 @@ from symbols import PRODUCTS, product_category, product_has_night_session
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 权益低于该值时,仅允许下列品种(可开仓列表、品种下拉、开仓报单)
|
||||
SMALL_ACCOUNT_CAPITAL_MAX = 100_000.0
|
||||
SMALL_ACCOUNT_PRODUCT_THS = frozenset({"c", "m", "MA", "rb"})
|
||||
SMALL_ACCOUNT_SCOPE_LABEL = "玉米、豆粕、甲醇、螺纹钢"
|
||||
|
||||
|
||||
def normalize_product_ths(ths: str) -> str:
|
||||
import re
|
||||
s = (ths or "").strip()
|
||||
m = re.match(r"^([A-Za-z]+)", s)
|
||||
return m.group(1) if m else s
|
||||
|
||||
|
||||
def is_small_account(capital: float) -> bool:
|
||||
cap = float(capital or 0)
|
||||
return 0 < cap <= SMALL_ACCOUNT_CAPITAL_MAX
|
||||
|
||||
|
||||
def product_in_small_account_whitelist(ths_or_product) -> bool:
|
||||
if isinstance(ths_or_product, dict):
|
||||
key = (ths_or_product.get("ths") or "").strip()
|
||||
else:
|
||||
key = normalize_product_ths(str(ths_or_product or ""))
|
||||
if not key:
|
||||
return False
|
||||
root = normalize_product_ths(key)
|
||||
if root in SMALL_ACCOUNT_PRODUCT_THS:
|
||||
return True
|
||||
upper = root.upper()
|
||||
return upper in {x.upper() for x in SMALL_ACCOUNT_PRODUCT_THS}
|
||||
|
||||
|
||||
def assert_product_allowed_for_capital(ths: str, capital: float) -> Optional[str]:
|
||||
"""小账户品种白名单校验;通过返回 None。"""
|
||||
if not is_small_account(capital):
|
||||
return None
|
||||
if product_in_small_account_whitelist(ths):
|
||||
return None
|
||||
return f"权益 10 万以下仅可交易:{SMALL_ACCOUNT_SCOPE_LABEL}"
|
||||
|
||||
|
||||
def filter_products_for_capital(products: list[dict], capital: float) -> list[dict]:
|
||||
if not is_small_account(capital):
|
||||
return list(products)
|
||||
return [p for p in products if product_in_small_account_whitelist(p)]
|
||||
|
||||
|
||||
def _attach_turnover(row: dict) -> None:
|
||||
"""成交额 = 昨日成交量(手) × 昨收 × 合约乘数。"""
|
||||
@@ -60,6 +106,23 @@ def assess_product_for_capital(
|
||||
cap = float(capital or 0)
|
||||
margin_pct = max(1.0, min(100.0, float(max_margin_pct or 30.0)))
|
||||
|
||||
if is_small_account(cap) and not product_in_small_account_whitelist(product):
|
||||
return {
|
||||
"ths": ths,
|
||||
"name": name,
|
||||
"exchange": exchange,
|
||||
"category": category,
|
||||
"mult": spec["mult"],
|
||||
"tick_size": tick,
|
||||
"status": "blocked",
|
||||
"status_label": f"10万以下限{SMALL_ACCOUNT_SCOPE_LABEL}",
|
||||
"min_capital_one_lot": None,
|
||||
"margin_one_lot": None,
|
||||
"max_lots": 0,
|
||||
"risk_one_lot_1pct": None,
|
||||
"has_night_session": product_has_night_session(product),
|
||||
}
|
||||
|
||||
if p <= 0:
|
||||
return {
|
||||
"ths": ths,
|
||||
@@ -173,5 +236,6 @@ def list_product_recommendations(
|
||||
}
|
||||
|
||||
with ThreadPoolExecutor(max_workers=10) as pool:
|
||||
rows = list(pool.map(_one, PRODUCTS))
|
||||
products = filter_products_for_capital(PRODUCTS, capital)
|
||||
rows = list(pool.map(_one, products))
|
||||
return sort_recommend_by_trend(rows)
|
||||
|
||||
Reference in New Issue
Block a user