programgarden 2.6.6__tar.gz → 2.7.0__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.
Files changed (75) hide show
  1. {programgarden-2.6.6 → programgarden-2.7.0}/PKG-INFO +16 -5
  2. {programgarden-2.6.6 → programgarden-2.7.0}/README.md +12 -1
  3. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/workflow_position_tracker.py +2 -1
  4. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/deep_fixtures.py +12 -6
  5. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/executor.py +368 -86
  6. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/replay_external.py +60 -1
  7. programgarden-2.7.0/programgarden/replay_responders.py +148 -0
  8. programgarden-2.7.0/programgarden/replay_tape.py +182 -0
  9. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/resolver.py +3 -3
  10. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/validation_replay.py +28 -1
  11. {programgarden-2.6.6 → programgarden-2.7.0}/pyproject.toml +4 -4
  12. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/__init__.py +0 -0
  13. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/binding_provenance.py +0 -0
  14. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/binding_validator.py +0 -0
  15. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/client.py +0 -0
  16. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/code_worker.py +0 -0
  17. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/context.py +0 -0
  18. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/__init__.py +0 -0
  19. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/adjustment_delivery.py +0 -0
  20. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/broker_evidence.py +0 -0
  21. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/broker_order_totals.py +0 -0
  22. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/broker_snapshot.py +0 -0
  23. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/checkpoint_manager.py +0 -0
  24. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/db_naming.py +0 -0
  25. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/execution_storage.py +0 -0
  26. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/fill_reconciler.py +0 -0
  27. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/order_cancellation.py +0 -0
  28. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/order_recovery.py +0 -0
  29. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/owned_order_cancellation.py +0 -0
  30. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/position_reconciliation.py +0 -0
  31. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/query_builder.py +0 -0
  32. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/sqlite_scope.py +0 -0
  33. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/database/workflow_risk_tracker.py +0 -0
  34. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/futures_contract_info.py +0 -0
  35. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/futures_exchange.py +0 -0
  36. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/futures_history.py +0 -0
  37. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/futures_orderable.py +0 -0
  38. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/futures_pnl.py +0 -0
  39. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/futures_read_evidence.py +0 -0
  40. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/incremental_build.py +0 -0
  41. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/managed_order_control.py +0 -0
  42. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/node_runner.py +0 -0
  43. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/order_lifecycle.py +0 -0
  44. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/paper_futures_business_date.py +0 -0
  45. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/plugin/__init__.py +0 -0
  46. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/plugin/sandbox.py +0 -0
  47. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/providers/__init__.py +0 -0
  48. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/providers/llm_errors.py +0 -0
  49. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/providers/llm_provider.py +0 -0
  50. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/ranking_nodes.py +0 -0
  51. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/reconnect_handler.py +0 -0
  52. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/replay_contracts.py +0 -0
  53. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/replay_events.py +0 -0
  54. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/replay_order_adapter.py +0 -0
  55. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/replay_orders.py +0 -0
  56. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/replay_scenarios.py +0 -0
  57. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/replay_semantics.py +0 -0
  58. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/replay_sources.py +0 -0
  59. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/replay_sqlite.py +0 -0
  60. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/replay_triggers.py +0 -0
  61. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/resource/__init__.py +0 -0
  62. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/resource/context.py +0 -0
  63. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/resource/limiter.py +0 -0
  64. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/resource/monitor.py +0 -0
  65. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/resource/throttle.py +0 -0
  66. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/semantic_rules.py +0 -0
  67. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/tools/__init__.py +0 -0
  68. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/tools/credential_tools.py +0 -0
  69. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/tools/definition_tools.py +0 -0
  70. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/tools/event_tools.py +0 -0
  71. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/tools/job_tools.py +0 -0
  72. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/tools/registry_tools.py +0 -0
  73. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/tools/sqlite_tools.py +0 -0
  74. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/validation_recommender.py +0 -0
  75. {programgarden-2.6.6 → programgarden-2.7.0}/programgarden/valuation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: programgarden
3
- Version: 2.6.6
3
+ Version: 2.7.0
4
4
  Summary: ProgramGarden - 노드 기반 자동매매 DSL 실행 엔진
5
5
  License-Expression: AGPL-3.0-or-later
6
6
  Author: 프로그램동산
@@ -15,9 +15,9 @@ Requires-Dist: aiosqlite (>=0.20.0,<0.21.0)
15
15
  Requires-Dist: croniter (>=6.0.0,<7.0.0)
16
16
  Requires-Dist: litellm (>=1.40.0)
17
17
  Requires-Dist: lxml (>=6.0.2,<7.0.0)
18
- Requires-Dist: programgarden-community (>=2.3.1,<3.0.0)
19
- Requires-Dist: programgarden-core (>=2.6.3,<3.0.0)
20
- Requires-Dist: programgarden-finance (>=2.0.3,<3.0.0)
18
+ Requires-Dist: programgarden-community (>=2.3.2,<3.0.0)
19
+ Requires-Dist: programgarden-core (>=2.7.0,<3.0.0)
20
+ Requires-Dist: programgarden-finance (>=2.0.6,<3.0.0)
21
21
  Requires-Dist: psutil (>=6.0.0,<7.0.0)
22
22
  Requires-Dist: psycopg2-binary (>=2.9.11,<3.0.0)
23
23
  Requires-Dist: pydantic (>=2.0.1,<3.0.0)
@@ -31,6 +31,13 @@ The 2.6.2 release candidate [futures minute alias correction](../../docs/futures
31
31
 
32
32
  # ProgramGarden
33
33
 
34
+ The 2.6.7 release [futures TC2 confirmation handling](../../docs/release-2.6.7-validation.md)
35
+ requires programgarden-finance 2.0.5, which reads overseas futures modify and
36
+ cancel confirmations (TC2) as LS sends them and re-registers account events
37
+ after a reconnect. The engine finds the workflow's order through
38
+ `orgn_ordr_no`, uses the guide's side codes and skips frames the SDK could
39
+ not read.
40
+
34
41
  The 2.6.6 release candidate [ranking nodes and runtime-values-as-data correction](../../docs/release-2.6.6-validation.md)
35
42
  adds KoreaStockRankingNode and OverseasStockRankingNode, evaluates only
36
43
  expression templates authored in the workflow, routes Gemini and DeepSeek
@@ -205,7 +212,11 @@ exchange execution numbers and broker execution numbers are not interchangeable.
205
212
  This ledger API alone does not reconcile finite workflows after their shutdown.
206
213
 
207
214
  Standalone futures TC3 callbacks interpret `s_b_ccd="1"` as sell and `"2"` as buy,
208
- matching the SDK contract. Unknown or blank side codes are logged and skipped
215
+ matching the SDK contract. TC2 confirmations use the same codes and find the
216
+ workflow's order through `orgn_ordr_no`: a futures modify or cancel gets its own
217
+ new order number (LS paper, 2026-10-15), so the cancel confirmation cancels the
218
+ original order in the ledger and a modify confirmation updates the successor row
219
+ recorded by ModifyOrderNodeExecutor. Unknown or blank side codes are logged and skipped
209
220
  before any inventory write is scheduled. With an app order lifecycle handler,
210
221
  TC3 still bypasses this legacy fill path: canonical REST reconciliation remains
211
222
  the sole writer. This side correction does not establish an alias between TC3
@@ -2,6 +2,13 @@ The 2.6.2 release candidate [futures minute alias correction](../../docs/futures
2
2
 
3
3
  # ProgramGarden
4
4
 
5
+ The 2.6.7 release [futures TC2 confirmation handling](../../docs/release-2.6.7-validation.md)
6
+ requires programgarden-finance 2.0.5, which reads overseas futures modify and
7
+ cancel confirmations (TC2) as LS sends them and re-registers account events
8
+ after a reconnect. The engine finds the workflow's order through
9
+ `orgn_ordr_no`, uses the guide's side codes and skips frames the SDK could
10
+ not read.
11
+
5
12
  The 2.6.6 release candidate [ranking nodes and runtime-values-as-data correction](../../docs/release-2.6.6-validation.md)
6
13
  adds KoreaStockRankingNode and OverseasStockRankingNode, evaluates only
7
14
  expression templates authored in the workflow, routes Gemini and DeepSeek
@@ -176,7 +183,11 @@ exchange execution numbers and broker execution numbers are not interchangeable.
176
183
  This ledger API alone does not reconcile finite workflows after their shutdown.
177
184
 
178
185
  Standalone futures TC3 callbacks interpret `s_b_ccd="1"` as sell and `"2"` as buy,
179
- matching the SDK contract. Unknown or blank side codes are logged and skipped
186
+ matching the SDK contract. TC2 confirmations use the same codes and find the
187
+ workflow's order through `orgn_ordr_no`: a futures modify or cancel gets its own
188
+ new order number (LS paper, 2026-10-15), so the cancel confirmation cancels the
189
+ original order in the ledger and a modify confirmation updates the successor row
190
+ recorded by ModifyOrderNodeExecutor. Unknown or blank side codes are logged and skipped
180
191
  before any inventory write is scheduled. With an app order lifecycle handler,
181
192
  TC3 still bypasses this legacy fill path: canonical REST reconciliation remains
182
193
  the sole writer. This side correction does not establish an alias between TC3
@@ -2725,7 +2725,7 @@ class WorkflowPositionTracker:
2725
2725
  with sqlite3.connect(self.db_path) as conn:
2726
2726
  cursor = conn.cursor()
2727
2727
  cursor.execute("""
2728
- SELECT order_no, order_date, symbol, exchange, side, quantity
2728
+ SELECT order_no, order_date, symbol, exchange, side, quantity, product
2729
2729
  FROM workflow_orders
2730
2730
  WHERE trading_mode = ? AND (price = 0 OR price IS NULL)
2731
2731
  ORDER BY created_at DESC
@@ -2739,6 +2739,7 @@ class WorkflowPositionTracker:
2739
2739
  "exchange": row[3],
2740
2740
  "side": row[4],
2741
2741
  "quantity": row[5],
2742
+ "product": row[6],
2742
2743
  }
2743
2744
  for row in cursor.fetchall()
2744
2745
  ]
@@ -79,7 +79,8 @@ def _config_symbols(config: Dict[str, Any]) -> Any:
79
79
  _FIXTURE_BARS = 64
80
80
 
81
81
 
82
- def _ohlcv_series(symbol: str, *, n: int = _FIXTURE_BARS, base: float = 100.0) -> List[Dict[str, Any]]:
82
+ def _ohlcv_series(symbol: str, *, n: int = _FIXTURE_BARS, base: float = 100.0,
83
+ minute_step: Optional[int] = None) -> List[Dict[str, Any]]:
83
84
  """Build a deterministic OHLCV series for one symbol (oldest bar first).
84
85
 
85
86
  The close path rises for the first ~⅔ of the window then declines into the
@@ -93,6 +94,9 @@ def _ohlcv_series(symbol: str, *, n: int = _FIXTURE_BARS, base: float = 100.0) -
93
94
  price = base
94
95
  for i in range(n):
95
96
  day = _FIXTURE_ANCHOR + timedelta(days=i)
97
+ if minute_step:
98
+ # Minute bars carry YYYYMMDDHHMMSS stamps, like the live g3203/o3103 rows.
99
+ day = _FIXTURE_ANCHOR.replace(hour=9, minute=30) + timedelta(minutes=i * minute_step)
96
100
  # Rise toward the peak, then ease back down — a gentle mean-reverting arc.
97
101
  if i <= peak:
98
102
  price = base + i * 0.8
@@ -101,7 +105,7 @@ def _ohlcv_series(symbol: str, *, n: int = _FIXTURE_BARS, base: float = 100.0) -
101
105
  price = max(price, base * 0.5)
102
106
  bars.append(
103
107
  {
104
- "date": day.strftime("%Y%m%d"),
108
+ "date": day.strftime("%Y%m%d%H%M%S" if minute_step else "%Y%m%d"),
105
109
  "open": round(price - 0.5, 2),
106
110
  "high": round(price + 1.0, 2),
107
111
  "low": round(price - 1.0, 2),
@@ -112,7 +116,8 @@ def _ohlcv_series(symbol: str, *, n: int = _FIXTURE_BARS, base: float = 100.0) -
112
116
  return bars
113
117
 
114
118
 
115
- def _time_series_entries(config: Dict[str, Any], symbols_raw: Any = None) -> List[Dict[str, Any]]:
119
+ def _time_series_entries(config: Dict[str, Any], symbols_raw: Any = None,
120
+ minute_step: Optional[int] = None) -> List[Dict[str, Any]]:
116
121
  """Build the per-symbol ``{symbol, exchange, time_series:[bars]}`` list that
117
122
  HistoricalDataNode emits at runtime. Downstream ConditionNode auto-iterates
118
123
  this list, so each entry must carry the keys its ``items.extract`` reads
@@ -125,7 +130,7 @@ def _time_series_entries(config: Dict[str, Any], symbols_raw: Any = None) -> Lis
125
130
  {
126
131
  "symbol": entry["symbol"],
127
132
  "exchange": entry["exchange"],
128
- "time_series": _ohlcv_series(entry["symbol"], base=100.0 + idx * 10),
133
+ "time_series": _ohlcv_series(entry["symbol"], base=100.0 + idx * 10, minute_step=minute_step),
129
134
  }
130
135
  )
131
136
  return entries
@@ -179,7 +184,8 @@ def market_data_fixture(config: Dict[str, Any], symbols_raw: Any = None, *, prod
179
184
  return {"values": values}
180
185
 
181
186
 
182
- def historical_data_fixture(config: Dict[str, Any], symbols_raw: Any = None) -> Dict[str, Any]:
187
+ def historical_data_fixture(config: Dict[str, Any], symbols_raw: Any = None, *,
188
+ minute_step: Optional[int] = None) -> Dict[str, Any]:
183
189
  """HistoricalDataNode deep fixture.
184
190
 
185
191
  Real shape (executor.py ``HistoricalDataNodeExecutor.execute`` return):
@@ -195,7 +201,7 @@ def historical_data_fixture(config: Dict[str, Any], symbols_raw: Any = None) ->
195
201
  """
196
202
  if symbols_raw is None:
197
203
  symbols_raw = config.get("symbol") or _config_symbols(config)
198
- entries = _time_series_entries(config, symbols_raw)
204
+ entries = _time_series_entries(config, symbols_raw, minute_step=minute_step)
199
205
  single = entries[0] if len(entries) == 1 else None
200
206
  return {
201
207
  "value": single,