fix bug
This commit is contained in:
BIN
py-client/libs/__pycache__/collector.cpython-311.pyc
Normal file
BIN
py-client/libs/__pycache__/collector.cpython-311.pyc
Normal file
Binary file not shown.
BIN
py-client/libs/__pycache__/dataset.cpython-311.pyc
Normal file
BIN
py-client/libs/__pycache__/dataset.cpython-311.pyc
Normal file
Binary file not shown.
42
py-client/libs/collector.py
Normal file
42
py-client/libs/collector.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
from dataclasses import asdict, is_dataclass
|
||||||
|
from datetime import date, datetime
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
|
||||||
|
COLLECTOR_URL = "http://139.224.247.176:13499/collector"
|
||||||
|
|
||||||
|
|
||||||
|
def _json_value(value: Any) -> Any:
|
||||||
|
"""Convert the QMT model values into values accepted by a JSON encoder."""
|
||||||
|
if is_dataclass(value) and not isinstance(value, type):
|
||||||
|
return _json_value(asdict(value))
|
||||||
|
if isinstance(value, dict):
|
||||||
|
return {str(key): _json_value(item) for key, item in value.items()}
|
||||||
|
if isinstance(value, (list, tuple, set)):
|
||||||
|
return [_json_value(item) for item in value]
|
||||||
|
if isinstance(value, Enum):
|
||||||
|
return _json_value(value.value)
|
||||||
|
if isinstance(value, (datetime, date)):
|
||||||
|
return value.isoformat()
|
||||||
|
if value is None or isinstance(value, (str, int, float, bool)):
|
||||||
|
return value
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def collector_push(account_id: str, assets: Any, positions: Any) -> None:
|
||||||
|
"""Best-effort collector upload; never propagate errors to the caller."""
|
||||||
|
try:
|
||||||
|
payload = _json_value(
|
||||||
|
{
|
||||||
|
"account_id": account_id,
|
||||||
|
"assets": assets,
|
||||||
|
"positions": positions,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
httpx.post(COLLECTOR_URL, json=payload, timeout=3.0)
|
||||||
|
except BaseException:
|
||||||
|
# Collection must never interrupt or affect the trading workflow.
|
||||||
|
pass
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
def dataset_push(assets:any,positions:any):
|
|
||||||
pass
|
|
||||||
@@ -26,7 +26,6 @@ def refresh_market(api_host: str = API_HOST) -> str:
|
|||||||
result = status(get_json(url, HTTP_TIMEOUT))
|
result = status(get_json(url, HTTP_TIMEOUT))
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
result = "UNKNOWN"
|
result = "UNKNOWN"
|
||||||
logging.error("获取大盘指数失败: %s %s", url, exc)
|
|
||||||
with _market_lock:
|
with _market_lock:
|
||||||
_market_status = result
|
_market_status = result
|
||||||
return result
|
return result
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -14,7 +14,7 @@ import config
|
|||||||
from libs.calc import trading_time
|
from libs.calc import trading_time
|
||||||
from libs.market import market_allow_open
|
from libs.market import market_allow_open
|
||||||
from libs.signal import init_signals, SignalItem
|
from libs.signal import init_signals, SignalItem
|
||||||
from libs.dataset import dataset_push
|
from libs.collector import collector_push
|
||||||
from sdk import Client
|
from sdk import Client
|
||||||
from libs.grid_take_profit import GridTrailingTracker
|
from libs.grid_take_profit import GridTrailingTracker
|
||||||
from .state import State
|
from .state import State
|
||||||
@@ -37,7 +37,6 @@ def Overview(assets, positions, account_cfg=None) -> None:
|
|||||||
else:
|
else:
|
||||||
log.warning("[启动] 获取资金概览失败")
|
log.warning("[启动] 获取资金概览失败")
|
||||||
|
|
||||||
log.info("[启动] 持仓数量=%d", len(positions))
|
|
||||||
for position in positions:
|
for position in positions:
|
||||||
if position.volume <= 0:
|
if position.volume <= 0:
|
||||||
continue
|
continue
|
||||||
@@ -131,7 +130,8 @@ def RunOnce(run: Runtime, signals:list[SignalItem]) -> None:
|
|||||||
(
|
(
|
||||||
"数据提交",
|
"数据提交",
|
||||||
run.executor.submit(
|
run.executor.submit(
|
||||||
dataset_push,
|
collector_push,
|
||||||
|
run.account_cfg.account_id,
|
||||||
assets,
|
assets,
|
||||||
positions,
|
positions,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import logging as log
|
|||||||
|
|
||||||
def open_signal(run:Runtime, ticks, open_signals) -> None:
|
def open_signal(run:Runtime, ticks, open_signals) -> None:
|
||||||
"""逐个验证开仓信号并提交买入委托。"""
|
"""逐个验证开仓信号并提交买入委托。"""
|
||||||
log.info("[Open] 信号总数:%d", len(open_signals))
|
|
||||||
for item in open_signals:
|
for item in open_signals:
|
||||||
# 1. 验证信号配置允许开仓的时间区间。
|
# 1. 验证信号配置允许开仓的时间区间。
|
||||||
signal_config = run.global_cfg.signals.get(item.signal_key)
|
signal_config = run.global_cfg.signals.get(item.signal_key)
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ def manage_positions(
|
|||||||
code = position.stock_code
|
code = position.stock_code
|
||||||
tick = ticks.get(code)
|
tick = ticks.get(code)
|
||||||
if code in runtime.account_cfg.excluded_codes:
|
if code in runtime.account_cfg.excluded_codes:
|
||||||
log.info("[Position] 代码=%s,名称=%s,止盈=跳过,补仓=跳过,原因=已配置为排除股票", code, position.stock_name)
|
log.info("[Position - ] 代码=%s,名称=%s,止盈=跳过,补仓=跳过,原因=已配置为排除股票", code, position.stock_name)
|
||||||
continue
|
continue
|
||||||
if (
|
if (
|
||||||
not code
|
not code
|
||||||
@@ -56,7 +56,7 @@ def manage_positions(
|
|||||||
or tick is None
|
or tick is None
|
||||||
or tick.last_price <= 0
|
or tick.last_price <= 0
|
||||||
):
|
):
|
||||||
log.warning("[Position] 代码=%s,名称=%s,止盈=跳过,补仓=跳过,原因=持仓或行情数据无效", code or "未知", position.stock_name)
|
log.warning("[Position - ] 代码=%s,名称=%s,止盈=跳过,补仓=跳过,原因=持仓或行情数据无效", code or "未知", position.stock_name)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
pnl_rate = round(
|
pnl_rate = round(
|
||||||
@@ -86,8 +86,14 @@ def manage_positions(
|
|||||||
elif runtime.account_cfg.enable_loss_add_position:
|
elif runtime.account_cfg.enable_loss_add_position:
|
||||||
loss_add_action = "大盘信号不允许"
|
loss_add_action = "大盘信号不允许"
|
||||||
|
|
||||||
|
if pnl_rate>=0:
|
||||||
log.info(
|
log.info(
|
||||||
"[Position] 代码=%s,名称=%s,盈亏=%.2f%%,止盈=%s,补仓=%s",
|
"[Position ↑ ] 代码=%s,名称=%s,盈亏=%.2f%%,止盈=%s,补仓=%s",
|
||||||
|
code, position.stock_name, pnl_rate, profit_action, loss_add_action,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
log.info(
|
||||||
|
"[Position ↓ ] 代码=%s,名称=%s,盈亏=%.2f%%,止盈=%s,补仓=%s",
|
||||||
code, position.stock_name, pnl_rate, profit_action, loss_add_action,
|
code, position.stock_name, pnl_rate, profit_action, loss_add_action,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class DipWatch:
|
|||||||
|
|
||||||
rebound = (price - watch.last_close) / watch.last_close * 100
|
rebound = (price - watch.last_close) / watch.last_close * 100
|
||||||
if rebound < self.rebound_threshold:
|
if rebound < self.rebound_threshold:
|
||||||
log.debug(
|
log.info(
|
||||||
"[%s Watch] %s 等待反弹,收盘价=%.2f,现价=%.2f,反弹=%.2f%%,阈值=%.2f%%",
|
"[%s Watch] %s 等待反弹,收盘价=%.2f,现价=%.2f,反弹=%.2f%%,阈值=%.2f%%",
|
||||||
tag,
|
tag,
|
||||||
code,
|
code,
|
||||||
|
|||||||
Reference in New Issue
Block a user