programgarden-core 1.25.2__tar.gz → 1.26.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 (84) hide show
  1. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/PKG-INFO +23 -1
  2. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/README.md +22 -0
  3. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/bases/listener.py +33 -18
  4. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/pyproject.toml +1 -1
  5. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/__init__.py +0 -0
  6. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/bases/__init__.py +0 -0
  7. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/bases/client.py +0 -0
  8. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/bases/components.py +0 -0
  9. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/bases/mixins.py +0 -0
  10. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/bases/products.py +0 -0
  11. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/bases/sql.py +0 -0
  12. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/bases/storage.py +0 -0
  13. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/code_node.py +0 -0
  14. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/exceptions.py +0 -0
  15. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/expression/__init__.py +0 -0
  16. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/expression/evaluator.py +0 -0
  17. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/i18n/__init__.py +0 -0
  18. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/i18n/locales/en.json +0 -0
  19. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/i18n/locales/ko.json +0 -0
  20. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/i18n/translator.py +0 -0
  21. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/korea_alias.py +0 -0
  22. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/__init__.py +0 -0
  23. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/connection_rule.py +0 -0
  24. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/credential.py +0 -0
  25. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/edge.py +0 -0
  26. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/event.py +0 -0
  27. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/exchange.py +0 -0
  28. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/field_binding.py +0 -0
  29. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/job.py +0 -0
  30. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/order_diagnostics.py +0 -0
  31. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/plugin_resource.py +0 -0
  32. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/resilience.py +0 -0
  33. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/resource.py +0 -0
  34. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/validation.py +0 -0
  35. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/models/workflow.py +0 -0
  36. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/__init__.py +0 -0
  37. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/account_futures.py +0 -0
  38. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/account_korea_stock.py +0 -0
  39. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/account_stock.py +0 -0
  40. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/ai.py +0 -0
  41. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/backtest.py +0 -0
  42. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/backtest_futures.py +0 -0
  43. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/backtest_korea_stock.py +0 -0
  44. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/backtest_stock.py +0 -0
  45. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/base.py +0 -0
  46. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/broker.py +0 -0
  47. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/calculation.py +0 -0
  48. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/code.py +0 -0
  49. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/condition.py +0 -0
  50. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/data.py +0 -0
  51. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/data_futures.py +0 -0
  52. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/data_korea_stock.py +0 -0
  53. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/data_stock.py +0 -0
  54. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/display.py +0 -0
  55. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/event.py +0 -0
  56. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/fundamental_korea_stock.py +0 -0
  57. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/fundamental_stock.py +0 -0
  58. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/infra.py +0 -0
  59. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/market_external.py +0 -0
  60. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/market_status.py +0 -0
  61. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/open_orders_futures.py +0 -0
  62. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/open_orders_korea_stock.py +0 -0
  63. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/open_orders_stock.py +0 -0
  64. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/order.py +0 -0
  65. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/portfolio.py +0 -0
  66. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/realtime_futures.py +0 -0
  67. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/realtime_korea_stock.py +0 -0
  68. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/realtime_stock.py +0 -0
  69. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/risk.py +0 -0
  70. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/symbol.py +0 -0
  71. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/symbol_futures.py +0 -0
  72. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/symbol_korea_stock.py +0 -0
  73. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/symbol_stock.py +0 -0
  74. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/nodes/trigger.py +0 -0
  75. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/presets/__init__.py +0 -0
  76. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/presets/news_analyst.json +0 -0
  77. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/presets/risk_manager.json +0 -0
  78. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/presets/strategist.json +0 -0
  79. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/presets/technical_analyst.json +0 -0
  80. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/registry/__init__.py +0 -0
  81. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/registry/credential_registry.py +0 -0
  82. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/registry/node_registry.py +0 -0
  83. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/registry/plugin_registry.py +0 -0
  84. {programgarden_core-1.25.2 → programgarden_core-1.26.0}/programgarden_core/retry_executor.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: programgarden-core
3
- Version: 1.25.2
3
+ Version: 1.26.0
4
4
  Summary: ProgramGarden Core - 노드 기반 DSL 핵심 타입 정의
5
5
  License-Expression: AGPL-3.0-or-later
6
6
  Author: 프로그램동산
@@ -101,3 +101,25 @@ programgarden_core/
101
101
 
102
102
  자세한 변경 사항은 `CHANGELOG.md`를 참고하세요.
103
103
 
104
+ ## Workflow PnL event contract
105
+
106
+ Futures workflow PnL events preserve native gross estimates separately from
107
+ accounting results. `workflow_*`, `other_*`, `total_*`, account and competition
108
+ monetary/rate scalars remain null when accounting evidence is unavailable.
109
+ `pnl_by_currency` contains gross price-change subtotals by contract currency;
110
+ `monetary_positions` retains their basis/status and unmodified, unconfirmed
111
+ `broker_pnl_amount`. No fee, FX, margin/equity return or verified contest score
112
+ is inferred from these estimates. Actual zero and negative amounts are retained.
113
+ `currency` is null for mixed or unavailable currencies. Consumers must handle
114
+ nullable monetary fields and must not coerce them to zero.
115
+
116
+ `WorkflowPnLEvent.personal_metrics` is an optional versioned envelope for retained
117
+ local workflow executions. Version 1 includes `scope` (kind, product, provider,
118
+ trading mode), timezone-aware `as_of`, `basis`, executed-order count/status,
119
+ per-symbol/exchange/currency realized amounts/status, and unavailable MDD.
120
+ It is unverified personal evidence, independent of whole-account contest results.
121
+ Stock realized amounts are stored long-only FIFO gross values excluding fees;
122
+ unknown currency stays null. Futures monetary values and portfolio MDD require
123
+ accounting evidence absent from this ledger and remain null. Consumers must
124
+ preserve null/status and use the latest cumulative observation, not sum dates.
125
+
@@ -85,3 +85,25 @@ programgarden_core/
85
85
  ## 변경 로그
86
86
 
87
87
  자세한 변경 사항은 `CHANGELOG.md`를 참고하세요.
88
+
89
+ ## Workflow PnL event contract
90
+
91
+ Futures workflow PnL events preserve native gross estimates separately from
92
+ accounting results. `workflow_*`, `other_*`, `total_*`, account and competition
93
+ monetary/rate scalars remain null when accounting evidence is unavailable.
94
+ `pnl_by_currency` contains gross price-change subtotals by contract currency;
95
+ `monetary_positions` retains their basis/status and unmodified, unconfirmed
96
+ `broker_pnl_amount`. No fee, FX, margin/equity return or verified contest score
97
+ is inferred from these estimates. Actual zero and negative amounts are retained.
98
+ `currency` is null for mixed or unavailable currencies. Consumers must handle
99
+ nullable monetary fields and must not coerce them to zero.
100
+
101
+ `WorkflowPnLEvent.personal_metrics` is an optional versioned envelope for retained
102
+ local workflow executions. Version 1 includes `scope` (kind, product, provider,
103
+ trading mode), timezone-aware `as_of`, `basis`, executed-order count/status,
104
+ per-symbol/exchange/currency realized amounts/status, and unavailable MDD.
105
+ It is unverified personal evidence, independent of whole-account contest results.
106
+ Stock realized amounts are stored long-only FIFO gross values excluding fees;
107
+ unknown currency stays null. Futures monetary values and portfolio MDD require
108
+ accounting evidence absent from this ledger and remain null. Consumers must
109
+ preserve null/status and use the latest cumulative observation, not sum dates.
@@ -205,8 +205,11 @@ class WorkflowPnLEvent:
205
205
  WorkflowPnLEvent separates workflow positions from manual positions
206
206
  using FIFO (First-In-First-Out) tracking.
207
207
 
208
- Used for competition ranking where only workflow-generated trades
209
- should be counted for official scoring.
208
+ This is a local workflow observation. Official competition scoring requires
209
+ separate broker-verified accounting and must not trust this event alone.
210
+ Futures monetary scalars are unavailable until their accounting basis is
211
+ established. Native gross price-change estimates remain in pnl_by_currency
212
+ and monetary_positions, separately from unconfirmed broker-reported values.
210
213
 
211
214
  Attributes:
212
215
  job_id: Job identifier
@@ -295,9 +298,7 @@ class WorkflowPnLEvent:
295
298
  super().__init__(start_date="20260115") # 대회 시작일
296
299
 
297
300
  async def on_workflow_pnl_update(self, event: WorkflowPnLEvent) -> None:
298
- # Use workflow_pnl_rate for official competition ranking
299
- await update_leaderboard(event.job_id, event.workflow_pnl_rate)
300
- # Use competition_workflow_pnl_rate if start_date filtering is needed
301
+ # Display available local estimates without verifying a score.
301
302
  if event.competition_workflow_pnl_rate is not None:
302
303
  print(f"Competition P&L: {event.competition_workflow_pnl_rate}%")
303
304
  """
@@ -306,22 +307,22 @@ class WorkflowPnLEvent:
306
307
  product: str # "overseas_stock" | "overseas_futures" | "korea_stock"
307
308
 
308
309
  # Workflow position P&L
309
- workflow_pnl_rate: Union[Decimal, float]
310
- workflow_eval_amount: Union[Decimal, float]
311
- workflow_buy_amount: Union[Decimal, float]
312
- workflow_pnl_amount: Union[Decimal, float]
310
+ workflow_pnl_rate: Optional[Union[Decimal, float]]
311
+ workflow_eval_amount: Optional[Union[Decimal, float]]
312
+ workflow_buy_amount: Optional[Union[Decimal, float]]
313
+ workflow_pnl_amount: Optional[Union[Decimal, float]]
313
314
 
314
315
  # Other (manual/unknown) position P&L
315
- other_pnl_rate: Union[Decimal, float]
316
- other_eval_amount: Union[Decimal, float]
317
- other_buy_amount: Union[Decimal, float]
318
- other_pnl_amount: Union[Decimal, float]
316
+ other_pnl_rate: Optional[Union[Decimal, float]]
317
+ other_eval_amount: Optional[Union[Decimal, float]]
318
+ other_buy_amount: Optional[Union[Decimal, float]]
319
+ other_pnl_amount: Optional[Union[Decimal, float]]
319
320
 
320
321
  # Total account P&L
321
- total_pnl_rate: Union[Decimal, float]
322
- total_eval_amount: Union[Decimal, float]
323
- total_buy_amount: Union[Decimal, float]
324
- total_pnl_amount: Union[Decimal, float]
322
+ total_pnl_rate: Optional[Union[Decimal, float]]
323
+ total_eval_amount: Optional[Union[Decimal, float]]
324
+ total_buy_amount: Optional[Union[Decimal, float]]
325
+ total_pnl_amount: Optional[Union[Decimal, float]]
325
326
 
326
327
  # Position details
327
328
  workflow_positions: list = field(default_factory=list) # List[PositionDetail]
@@ -335,9 +336,19 @@ class WorkflowPnLEvent:
335
336
  paper_trading: bool = False # True: 모의투자, False: 실전투자
336
337
 
337
338
  # Metadata
338
- currency: str = "USD"
339
+ currency: Optional[str] = "USD"
339
340
  timestamp: datetime = field(default_factory=datetime.utcnow)
340
341
 
342
+ # Native estimates and broker observations are distinct from account returns.
343
+ monetary_status: Optional[str] = None
344
+ monetary_basis: Optional[str] = None
345
+ monetary_unavailable_reason: Optional[str] = None
346
+ pnl_by_currency: Dict[str, Any] = field(default_factory=dict)
347
+ monetary_positions: Dict[str, Any] = field(default_factory=dict)
348
+ unavailable_position_count: int = 0
349
+ # Unverified retained workflow executions; separate from account/contest PnL.
350
+ personal_metrics: Optional[Dict[str, Any]] = None
351
+
341
352
  # ========== NEW FIELDS (v2.0) ==========
342
353
 
343
354
  # Workflow product-specific P&L
@@ -890,6 +901,10 @@ class ConsoleExecutionListener(BaseExecutionListener):
890
901
 
891
902
  async def on_workflow_pnl_update(self, event: WorkflowPnLEvent) -> None:
892
903
  """Print workflow P&L update for debugging"""
904
+ if event.workflow_pnl_rate is None or event.total_pnl_rate is None:
905
+ print(f"[{event.broker_node_id}] Workflow/account return unavailable "
906
+ f"({event.monetary_unavailable_reason or 'missing monetary evidence'})")
907
+ return
893
908
  wf_pnl = float(event.workflow_pnl_rate)
894
909
  total_pnl = float(event.total_pnl_rate)
895
910
 
@@ -5,7 +5,7 @@ authors = [
5
5
  homepage = "https://programgarden.com"
6
6
  requires-python = ">=3.12"
7
7
  name = "programgarden-core"
8
- version = "1.25.2"
8
+ version = "1.26.0"
9
9
  license = "AGPL-3.0-or-later"
10
10
  description = "ProgramGarden Core - 노드 기반 DSL 핵심 타입 정의"
11
11
  readme = "README.md"