programgarden 1.37.5__tar.gz → 1.37.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {programgarden-1.37.5 → programgarden-1.37.7}/PKG-INFO +12 -1
- {programgarden-1.37.5 → programgarden-1.37.7}/README.md +11 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/executor.py +55 -7
- {programgarden-1.37.5 → programgarden-1.37.7}/pyproject.toml +1 -1
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/__init__.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/binding_validator.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/client.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/code_worker.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/context.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/database/__init__.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/database/checkpoint_manager.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/database/fill_reconciler.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/database/query_builder.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/database/workflow_position_tracker.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/database/workflow_risk_tracker.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/deep_fixtures.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/futures_pnl.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/node_runner.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/order_lifecycle.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/plugin/__init__.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/plugin/sandbox.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/providers/__init__.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/providers/llm_errors.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/providers/llm_provider.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/reconnect_handler.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/resolver.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/resource/__init__.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/resource/context.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/resource/limiter.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/resource/monitor.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/resource/throttle.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/semantic_rules.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/tools/__init__.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/tools/credential_tools.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/tools/definition_tools.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/tools/event_tools.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/tools/job_tools.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/tools/registry_tools.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/tools/sqlite_tools.py +0 -0
- {programgarden-1.37.5 → programgarden-1.37.7}/programgarden/validation_recommender.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: programgarden
|
|
3
|
-
Version: 1.37.
|
|
3
|
+
Version: 1.37.7
|
|
4
4
|
Summary: ProgramGarden - 노드 기반 자동매매 DSL 실행 엔진
|
|
5
5
|
License-Expression: AGPL-3.0-or-later
|
|
6
6
|
Author: 프로그램동산
|
|
@@ -96,12 +96,23 @@ Broker account trackers belong to the workflow job. Normal completion, `stop()`,
|
|
|
96
96
|
account polling, and close each tracker's dedicated WebSocket. Late account PnL
|
|
97
97
|
callbacks do not restart work after shutdown. This cleanup also covers partially
|
|
98
98
|
initialized trackers and leaves other jobs running.
|
|
99
|
+
Scheduled cycles reuse the same broker account tracker, including pending startup.
|
|
100
|
+
A failed startup stops its tracker and closes its connection before a later cycle
|
|
101
|
+
may try again; no immediate retry or extra workflow node is introduced.
|
|
99
102
|
Already queued or in-flight PnL notifications have up to one second to finish
|
|
100
103
|
after account trackers stop, before listeners close. On timeout, cleanup logs the
|
|
101
104
|
pending count and cancels those tasks, allowing another 0.25 seconds for cancellation.
|
|
102
105
|
A listener that suppresses cancellation is reported and remains tracked; it cannot
|
|
103
106
|
hold job shutdown indefinitely. Delivery beyond this bounded grace is not guaranteed.
|
|
104
107
|
|
|
108
|
+
Overseas-stock OpenOrdersNode treats the observed terminal COSAQ00102 `02679`
|
|
109
|
+
empty envelope as `open_orders=[]` / `count=0` without an error. The echoed date,
|
|
110
|
+
market and filters must match its current-day pending query, the empty detail
|
|
111
|
+
array must be explicitly present, and continuation must be terminal. This follows
|
|
112
|
+
the finance package's observed-response reference and StockAccountTracker;
|
|
113
|
+
`02679` is not a generic success code. Missing, malformed, mismatched and failed
|
|
114
|
+
reads retain `error` / `reason=fetch_failed` so workflows can block new entries.
|
|
115
|
+
|
|
105
116
|
For one-shot workflows, an unhandled `order_result.success=False` returned directly
|
|
106
117
|
by a main-flow node makes the final job status `failed` and emits `WORKFLOW_FAILED`.
|
|
107
118
|
The original broker message remains in node diagnostics and the failure statistics.
|
|
@@ -67,12 +67,23 @@ Broker account trackers belong to the workflow job. Normal completion, `stop()`,
|
|
|
67
67
|
account polling, and close each tracker's dedicated WebSocket. Late account PnL
|
|
68
68
|
callbacks do not restart work after shutdown. This cleanup also covers partially
|
|
69
69
|
initialized trackers and leaves other jobs running.
|
|
70
|
+
Scheduled cycles reuse the same broker account tracker, including pending startup.
|
|
71
|
+
A failed startup stops its tracker and closes its connection before a later cycle
|
|
72
|
+
may try again; no immediate retry or extra workflow node is introduced.
|
|
70
73
|
Already queued or in-flight PnL notifications have up to one second to finish
|
|
71
74
|
after account trackers stop, before listeners close. On timeout, cleanup logs the
|
|
72
75
|
pending count and cancels those tasks, allowing another 0.25 seconds for cancellation.
|
|
73
76
|
A listener that suppresses cancellation is reported and remains tracked; it cannot
|
|
74
77
|
hold job shutdown indefinitely. Delivery beyond this bounded grace is not guaranteed.
|
|
75
78
|
|
|
79
|
+
Overseas-stock OpenOrdersNode treats the observed terminal COSAQ00102 `02679`
|
|
80
|
+
empty envelope as `open_orders=[]` / `count=0` without an error. The echoed date,
|
|
81
|
+
market and filters must match its current-day pending query, the empty detail
|
|
82
|
+
array must be explicitly present, and continuation must be terminal. This follows
|
|
83
|
+
the finance package's observed-response reference and StockAccountTracker;
|
|
84
|
+
`02679` is not a generic success code. Missing, malformed, mismatched and failed
|
|
85
|
+
reads retain `error` / `reason=fetch_failed` so workflows can block new entries.
|
|
86
|
+
|
|
76
87
|
For one-shot workflows, an unhandled `order_result.success=False` returned directly
|
|
77
88
|
by a main-flow node makes the final job status `failed` and emits `WORKFLOW_FAILED`.
|
|
78
89
|
The original broker message remains in node diagnostics and the failure statistics.
|
|
@@ -5491,6 +5491,11 @@ class BrokerNodeExecutor(NodeExecutorBase):
|
|
|
5491
5491
|
로그인이라, 더미 secret 으로 도는 기기(트레이앱 검증 잡·서버 발급 모드)의 실제 실행에서
|
|
5492
5492
|
추적기만 403 으로 죽고 error 로그 뒤 추적 없이 진행됐다.
|
|
5493
5493
|
"""
|
|
5494
|
+
tracker_key = f"{context.job_id}_{node_id}"
|
|
5495
|
+
# Scheduled cycles revisit the broker. Keep its existing tracker (also
|
|
5496
|
+
# while startup awaits connect) instead of orphaning polling/WS resources.
|
|
5497
|
+
if context.is_shutdown or tracker_key in self._active_trackers:
|
|
5498
|
+
return
|
|
5494
5499
|
try:
|
|
5495
5500
|
from programgarden_finance import LS
|
|
5496
5501
|
|
|
@@ -5527,6 +5532,18 @@ class BrokerNodeExecutor(NodeExecutorBase):
|
|
|
5527
5532
|
|
|
5528
5533
|
except Exception as e:
|
|
5529
5534
|
context.log("error", f"Failed to start account tracking: {e}", node_id)
|
|
5535
|
+
# Failed startup must not leave an unusable entry that prevents a
|
|
5536
|
+
# later scheduled cycle from trying again. No immediate retry.
|
|
5537
|
+
info = self._active_trackers.get(tracker_key)
|
|
5538
|
+
if info is not None:
|
|
5539
|
+
for resource, method in ((info.get("tracker"), "stop"), (info.get("real"), "close")):
|
|
5540
|
+
if resource is not None:
|
|
5541
|
+
try:
|
|
5542
|
+
await getattr(resource, method)()
|
|
5543
|
+
except Exception as cleanup_error:
|
|
5544
|
+
logger.warning("Account tracker startup cleanup failed: %s", type(cleanup_error).__name__)
|
|
5545
|
+
if self._active_trackers.get(tracker_key) is info:
|
|
5546
|
+
self._active_trackers.pop(tracker_key)
|
|
5530
5547
|
|
|
5531
5548
|
async def _start_overseas_stock_tracker(
|
|
5532
5549
|
self,
|
|
@@ -6541,14 +6558,39 @@ class OpenOrdersNodeExecutor(NodeExecutorBase):
|
|
|
6541
6558
|
|
|
6542
6559
|
rows = response.block3 or []
|
|
6543
6560
|
usable_rows = [item for item in rows if item.OrdNo and item.OrdNo > 0]
|
|
6544
|
-
#
|
|
6545
|
-
#
|
|
6546
|
-
|
|
6561
|
+
# Match StockAccountTracker's observed pending-query envelope. The SDK
|
|
6562
|
+
# defaults missing details to []; only an explicit empty array is evidence.
|
|
6563
|
+
complete_empty = (
|
|
6547
6564
|
not rows
|
|
6548
|
-
and
|
|
6549
|
-
and
|
|
6550
|
-
and
|
|
6565
|
+
and "block3" in response.model_fields_set
|
|
6566
|
+
and response.block1 is not None
|
|
6567
|
+
and response.block2 is not None
|
|
6568
|
+
)
|
|
6569
|
+
echo = response.block1
|
|
6570
|
+
header = response.header
|
|
6571
|
+
# 02679 is not a generic success code. This exact terminal response was
|
|
6572
|
+
# observed for market 00 (echoed as %) and this current-day pending query;
|
|
6573
|
+
# see finance/docs/observed_broker_responses.md (2026-09-09).
|
|
6574
|
+
observed_no_data = (
|
|
6575
|
+
complete_empty and status == 200 and diagnostics["rsp_cd"] == "02679"
|
|
6576
|
+
and echo.OrdDt == today and echo.OrdMktCode == "%"
|
|
6577
|
+
and echo.ThdayBnsAppYn == "1" and echo.BnsTpCode == "0"
|
|
6578
|
+
and echo.CrcyCode == "000"
|
|
6579
|
+
and all(
|
|
6580
|
+
str(getattr(echo, name)) == expected
|
|
6581
|
+
for name, expected in (
|
|
6582
|
+
("QryTpCode", "1"), ("BkseqTpCode", "1"),
|
|
6583
|
+
("IsuNo", ""), ("SrtOrdNo", "999999999"),
|
|
6584
|
+
("ExecYn", "2"), ("LoanBalHldYn", "0"),
|
|
6585
|
+
)
|
|
6586
|
+
if name in echo.model_fields_set
|
|
6587
|
+
)
|
|
6588
|
+
and header is not None and header.tr_cont == "N"
|
|
6589
|
+
and not header.tr_cont_key
|
|
6551
6590
|
)
|
|
6591
|
+
valid_empty = complete_empty and (diagnostics["rsp_cd"] == "00000" or observed_no_data)
|
|
6592
|
+
if diagnostics["rsp_cd"] == "02679" and not observed_no_data:
|
|
6593
|
+
return unavailable()
|
|
6552
6594
|
if not usable_rows and not valid_empty:
|
|
6553
6595
|
return unavailable()
|
|
6554
6596
|
|
|
@@ -24533,9 +24575,15 @@ class WorkflowJob:
|
|
|
24533
24575
|
|
|
24534
24576
|
ls = entry["ls"]
|
|
24535
24577
|
node_id = "fill_reconciler"
|
|
24578
|
+
# 🔴 체결 조회는 `NewOrderNodeExecutor` 의 메서드다 — WorkflowJob 의 것이 아니다.
|
|
24579
|
+
# `self._query_...` 로 부르면 AttributeError 로 매 주기 죽는다(2026-09-14 실관측).
|
|
24580
|
+
# 같은 부류로 `_active_trackers`(BrokerNodeExecutor) 도 한 번 틀렸다. 이 파일은
|
|
24581
|
+
# 한 모듈에 여러 클래스가 있어 `self.` 이 어느 클래스인지 눈으로는 안 보인다 —
|
|
24582
|
+
# test_fill_reconcile_wiring.py 의 소유자 검증 테스트가 이걸 잠근다.
|
|
24583
|
+
order_executor = NewOrderNodeExecutor()
|
|
24536
24584
|
|
|
24537
24585
|
async def _fetch(order_date: str) -> Dict[str, Dict[str, Any]]:
|
|
24538
|
-
return await
|
|
24586
|
+
return await order_executor._query_overseas_stock_fills_by_date(
|
|
24539
24587
|
ls, order_date, self.context, node_id
|
|
24540
24588
|
)
|
|
24541
24589
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden-1.37.5 → programgarden-1.37.7}/programgarden/database/workflow_position_tracker.py
RENAMED
|
File without changes
|
{programgarden-1.37.5 → programgarden-1.37.7}/programgarden/database/workflow_risk_tracker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|