feat client.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,7 +10,9 @@ import time
|
||||
from datetime import datetime
|
||||
|
||||
import config
|
||||
from libs import init_signals, market_allow_open, trading_time
|
||||
from libs.calc import trading_time
|
||||
from libs.market import market_allow_open
|
||||
from libs.signal import init_signals, SignalItem
|
||||
from sdk import Client
|
||||
from libs.grid_take_profit import GridTrailingTracker
|
||||
from .state import State
|
||||
@@ -113,16 +115,18 @@ def StartTrend() -> None:
|
||||
time.sleep(max(0.0, 30.0 - elapsed))
|
||||
|
||||
|
||||
def RunOnce(run: Runtime, signals) -> None:
|
||||
def RunOnce(run: Runtime, signals:list[SignalItem]) -> None:
|
||||
"""按固定步骤执行一轮趋势策略, ``RunOnce``。"""
|
||||
if not trading_time(datetime.now()):
|
||||
return
|
||||
|
||||
# 1. 取消超过有效期仍未完成的委托订单。
|
||||
# 1. 刷新订单数据,清理过期订单。
|
||||
try:
|
||||
run.orders.refresh(run.client)
|
||||
except Exception:
|
||||
logging.exception("取消过期订单失败")
|
||||
return
|
||||
|
||||
|
||||
# 2. 验证可用资金;低于资金安全线时禁止开新仓。
|
||||
try:
|
||||
@@ -144,37 +148,25 @@ def RunOnce(run: Runtime, signals) -> None:
|
||||
logging.exception("获取持仓失败")
|
||||
return
|
||||
|
||||
# 每轮使用最新委托和成交恢复状态。查询或落盘失败时禁止继续开仓,
|
||||
# 避免在订单结果不明确的情况下提交重复买单。
|
||||
previous_state_codes = set(run.state.codes)
|
||||
# 5. 更新状态机
|
||||
try:
|
||||
broker_orders = run.client.trade_detail_data("order")
|
||||
run.state.reconcile(positions, broker_orders)
|
||||
run.state.reconcile(positions, run.orders.data)
|
||||
except Exception:
|
||||
logging.exception("订单状态对账失败,本轮禁止自动交易")
|
||||
return
|
||||
|
||||
removed_codes = previous_state_codes - set(run.state.codes)
|
||||
for code in removed_codes:
|
||||
run.open_watch.forget(code)
|
||||
run.add_watch.forget(code)
|
||||
|
||||
# 5. 验证有效开仓信号:排除已有持仓和未决订单。
|
||||
position_code_set = set(position_codes)
|
||||
allow_open = []
|
||||
seen_codes = position_code_set | set(run.state.unresolved_codes)
|
||||
# 6. 验证有效开仓信号:排除已有持仓和未决订单。
|
||||
allow_open: list[SignalItem] = []
|
||||
allow_codes: list[str] = []
|
||||
for signal in signals:
|
||||
if signal.code not in seen_codes:
|
||||
if signal.code not in position_codes:
|
||||
allow_open.append(signal)
|
||||
seen_codes.add(signal.code)
|
||||
allow_codes.append(signal.code)
|
||||
|
||||
# 6. 获取持仓和待开仓证券的实时行情 tick。
|
||||
all_codes = list(position_codes)
|
||||
all_codes.extend(
|
||||
signal.code for signal in allow_open if signal.code not in position_code_set
|
||||
)
|
||||
all_codes = allow_codes + position_codes
|
||||
try:
|
||||
ticks = run.client.full_tick(list(dict.fromkeys(all_codes)))
|
||||
ticks = run.client.full_tick(all_codes)
|
||||
except Exception:
|
||||
logging.exception("获取行情失败")
|
||||
return
|
||||
|
||||
@@ -7,18 +7,14 @@ from datetime import datetime
|
||||
|
||||
from libs import calc_buy_volume
|
||||
from sdk import OP_BUY
|
||||
|
||||
from .runtime import Runtime
|
||||
from .order import PlaceOrderRequest
|
||||
from .state import STATUS_ING, StateItem
|
||||
|
||||
|
||||
def open_signal(run, ticks, open_signals) -> None:
|
||||
def open_signal(run:Runtime, ticks, open_signals) -> None:
|
||||
"""逐个验证开仓信号并提交买入委托。"""
|
||||
for item in open_signals:
|
||||
# 候选生成后状态仍可能发生变化,提交前再次阻止未决订单重复开仓。
|
||||
if run.state.has_unresolved_order(item.code):
|
||||
continue
|
||||
|
||||
# 1. 验证信号配置允许开仓的时间区间。
|
||||
signal_config = run.global_cfg.signals.get(item.signal_key)
|
||||
if signal_config is None or not check_timezone(signal_config.timezone):
|
||||
@@ -34,44 +30,44 @@ def open_signal(run, ticks, open_signals) -> None:
|
||||
if price <= 0:
|
||||
continue
|
||||
|
||||
# 4. 等待价格从观察低点反弹,防止直接接下跌中的“飞刀”。
|
||||
if not run.open_watch.triggered("开仓", item.code, price):
|
||||
continue
|
||||
|
||||
# 5. 根据单笔买入金额计算整手开仓数量。
|
||||
volume = calc_buy_volume(price, run.account_cfg.buy_value)
|
||||
if volume <= 0:
|
||||
continue
|
||||
|
||||
# 6. 生成本地订单号并按最新价提交开仓委托。
|
||||
order_id = run.orders.new_order_id("base")
|
||||
request = PlaceOrderRequest(
|
||||
run.client,
|
||||
OP_BUY,
|
||||
item.code,
|
||||
volume,
|
||||
order_id,
|
||||
item.signal_key,
|
||||
)
|
||||
if not run.orders.place(request):
|
||||
# 当前价高于昨收价可开仓
|
||||
if signal_config.gt_last_price_is_open and item.last_close>0 and price>item.last_close:
|
||||
try:
|
||||
do_open(run,item.code,volume,item.signal_key)
|
||||
logging.info("[开仓] %s 买入 %d 股", item.code, volume)
|
||||
except Exception as e:
|
||||
logging.exception("[开仓] %s 失败: %s", item.code,e)
|
||||
continue
|
||||
|
||||
# 4. 等待价格从观察低点反弹,防止直接接下跌中的“飞刀”。
|
||||
if not run.open_watch.triggered("开仓", item.code, price):
|
||||
continue
|
||||
|
||||
# 7. 保存底仓订单、数量、成本和处理中状态。
|
||||
run.state.set(
|
||||
StateItem(
|
||||
code=item.code,
|
||||
base_order_id=order_id,
|
||||
base_qty=volume,
|
||||
base_cost=price,
|
||||
base_status=STATUS_ING,
|
||||
)
|
||||
)
|
||||
try:
|
||||
run.state.save()
|
||||
except OSError:
|
||||
logging.exception("[状态] %s 开仓状态保存失败", item.code)
|
||||
run.open_watch.forget(item.code)
|
||||
logging.info("[ZT][开仓] %s 买入 %d 股", item.code, volume)
|
||||
do_open(run,item.code,volume,item.signal_key)
|
||||
logging.info("[开仓] %s 买入 %d 股", item.code, volume)
|
||||
except Exception as e:
|
||||
logging.exception("[开仓] %s 失败: %s", item.code,e)
|
||||
|
||||
|
||||
def do_open(run:Runtime,code:str,volume:int,signal_key:str)->None:
|
||||
"""生成本地订单号并按最新价提交开仓委托。"""
|
||||
order_id = run.orders.new_order_id("base")
|
||||
request = PlaceOrderRequest(
|
||||
run.client,
|
||||
OP_BUY,
|
||||
code,
|
||||
volume,
|
||||
order_id,
|
||||
signal_key,
|
||||
)
|
||||
if not run.orders.place(request):
|
||||
raise RuntimeError("订单提交失败")
|
||||
|
||||
|
||||
def check_timezone(timezone: str, now: datetime | None = None) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user