feat client.
This commit is contained in:
71
py-client/strategy/zt/positions.py
Normal file
71
py-client/strategy/zt/positions.py
Normal file
@@ -0,0 +1,71 @@
|
||||
"""日内先卖后买的做 T 规则。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from libs.grid_take_profit import GridState
|
||||
from sdk import OP_BUY, OP_SELL, PositionItem
|
||||
from strategy.trend.order import PlaceOrderRequest
|
||||
|
||||
from .state import BUYING, READY, SELLING, SOLD
|
||||
|
||||
|
||||
def manage_positions(run, ticks, positions: list[PositionItem], available: float, today: str, force_buy_back: bool = False) -> None:
|
||||
for position in positions:
|
||||
code = position.stock_code
|
||||
tick = ticks.get(code)
|
||||
if not code or code in run.account_cfg.excluded_codes or tick is None:
|
||||
continue
|
||||
price = tick.last_price
|
||||
if price <= 0 or price > run.account_cfg.zt_max_price:
|
||||
continue
|
||||
try:
|
||||
state = run.state.get(code)
|
||||
except KeyError:
|
||||
continue
|
||||
if state.phase == READY and not force_buy_back:
|
||||
_try_sell(run, state, position, price, today)
|
||||
elif state.phase == SOLD:
|
||||
_try_buy_back(run, state, price, available, today, force_buy_back)
|
||||
|
||||
|
||||
def _try_sell(run, state, position: PositionItem, price: float, today: str) -> None:
|
||||
if state.base_cost <= 0 or run.orders.busy(state.code, "SELL"):
|
||||
return
|
||||
pnl_rate = (price - state.base_cost) / state.base_cost * 100
|
||||
observation = run.sell_tracker.observe(f"{run.account_cfg.account_id}:{state.code}", pnl_rate)
|
||||
if observation.state != GridState.RETREAT:
|
||||
return
|
||||
volume = min(position.can_use_volume, int(state.base_qty * run.account_cfg.zt_sell_ratio) // 100 * 100)
|
||||
if volume <= 0:
|
||||
return
|
||||
order_id = run.orders.new_order_id("t-sell")
|
||||
request = PlaceOrderRequest(run.client, OP_SELL, state.code, volume, order_id, run.account_cfg.strategy)
|
||||
if not run.orders.place(request):
|
||||
return
|
||||
state.trade_date, state.phase = today, SELLING
|
||||
state.sell_order_id, state.sell_qty, state.sell_price = order_id, volume, price
|
||||
run.state.set(state)
|
||||
run.state.save()
|
||||
logging.info("[ZT 卖出] %s %d 股,网格回撤触发", state.code, volume)
|
||||
|
||||
|
||||
def _try_buy_back(run, state, price: float, available: float, today: str, force: bool) -> None:
|
||||
target = state.sell_price * (1 - run.account_cfg.zt_buy_fall_pct / 100)
|
||||
if (not force and price > target) or run.orders.busy(state.code, "BUY"):
|
||||
return
|
||||
if state.sell_qty <= 0 or price * state.sell_qty > available:
|
||||
return
|
||||
if not force and not run.buy_watch.triggered("ZT 买回", state.code, price):
|
||||
return
|
||||
order_id = run.orders.new_order_id("t-buy")
|
||||
request = PlaceOrderRequest(run.client, OP_BUY, state.code, state.sell_qty, order_id, run.account_cfg.strategy)
|
||||
if not run.orders.place(request):
|
||||
return
|
||||
state.trade_date, state.phase, state.buy_order_id = today, BUYING, order_id
|
||||
run.state.set(state)
|
||||
run.state.save()
|
||||
run.buy_watch.forget(state.code)
|
||||
reason = "尾盘强制买回" if force else f"回撤 {run.account_cfg.zt_buy_fall_pct:.2f}% 后反弹确认"
|
||||
logging.info("[ZT 买回] %s %d 股,%s", state.code, state.sell_qty, reason)
|
||||
Reference in New Issue
Block a user