programgarden 1.37.8__tar.gz → 1.37.9__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.8 → programgarden-1.37.9}/PKG-INFO +3 -3
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/context.py +9 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/executor.py +3 -0
- programgarden-1.37.9/programgarden/valuation.py +51 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/pyproject.toml +3 -3
- {programgarden-1.37.8 → programgarden-1.37.9}/README.md +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/__init__.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/binding_validator.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/client.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/code_worker.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/database/__init__.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/database/checkpoint_manager.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/database/fill_reconciler.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/database/query_builder.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/database/workflow_position_tracker.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/database/workflow_risk_tracker.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/deep_fixtures.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/futures_pnl.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/node_runner.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/order_lifecycle.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/plugin/__init__.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/plugin/sandbox.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/providers/__init__.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/providers/llm_errors.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/providers/llm_provider.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/reconnect_handler.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/resolver.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/resource/__init__.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/resource/context.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/resource/limiter.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/resource/monitor.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/resource/throttle.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/semantic_rules.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/tools/__init__.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/tools/credential_tools.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/tools/definition_tools.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/tools/event_tools.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/tools/job_tools.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/tools/registry_tools.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/programgarden/tools/sqlite_tools.py +0 -0
- {programgarden-1.37.8 → programgarden-1.37.9}/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.9
|
|
4
4
|
Summary: ProgramGarden - 노드 기반 자동매매 DSL 실행 엔진
|
|
5
5
|
License-Expression: AGPL-3.0-or-later
|
|
6
6
|
Author: 프로그램동산
|
|
@@ -16,8 +16,8 @@ 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
18
|
Requires-Dist: programgarden-community (>=1.15.3,<2.0.0)
|
|
19
|
-
Requires-Dist: programgarden-core (>=1.28.
|
|
20
|
-
Requires-Dist: programgarden-finance (>=1.9.
|
|
19
|
+
Requires-Dist: programgarden-core (>=1.28.2,<2.0.0)
|
|
20
|
+
Requires-Dist: programgarden-finance (>=1.9.8,<2.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.0,<3.0.0)
|
|
@@ -1968,6 +1968,7 @@ class ExecutionContext:
|
|
|
1968
1968
|
current_prices: Dict[str, float],
|
|
1969
1969
|
account_positions: Optional[Dict[str, Any]],
|
|
1970
1970
|
currency: Optional[str] = "USD",
|
|
1971
|
+
account_valuation: Optional[Dict[str, Any]] = None,
|
|
1971
1972
|
) -> None:
|
|
1972
1973
|
"""Notify all listeners about workflow P&L update (확장 버전).
|
|
1973
1974
|
|
|
@@ -2015,6 +2016,12 @@ class ExecutionContext:
|
|
|
2015
2016
|
product=product,
|
|
2016
2017
|
start_date=None, # 전체 기간
|
|
2017
2018
|
)
|
|
2019
|
+
from .valuation import workflow_valuation_snapshot
|
|
2020
|
+
|
|
2021
|
+
workflow_valuation = workflow_valuation_snapshot(
|
|
2022
|
+
base_workflow_result,
|
|
2023
|
+
account_positions if account_positions is not None else ({} if account_valuation else None),
|
|
2024
|
+
now, product)
|
|
2018
2025
|
|
|
2019
2026
|
# 2. 계좌 전체 수익률 계산
|
|
2020
2027
|
account_result = self._calculate_account_pnl(
|
|
@@ -2098,6 +2105,8 @@ class ExecutionContext:
|
|
|
2098
2105
|
"anomaly_count": base_workflow_result.get("anomaly_count", 0),
|
|
2099
2106
|
"currency": currency,
|
|
2100
2107
|
"personal_metrics": personal_metrics,
|
|
2108
|
+
"account_valuation": account_valuation,
|
|
2109
|
+
"workflow_valuation": workflow_valuation,
|
|
2101
2110
|
|
|
2102
2111
|
# 신규 필드: 워크플로우 상품별
|
|
2103
2112
|
"workflow_overseas_stock_pnl_rate": base_workflow_result.get("workflow_overseas_stock_pnl_rate"),
|
|
@@ -5610,6 +5610,8 @@ class BrokerNodeExecutor(NodeExecutorBase):
|
|
|
5610
5610
|
"current_price": float(pos_item.current_price) if hasattr(pos_item, 'current_price') else 0,
|
|
5611
5611
|
"pnl_rate": float(pos_item.pnl_rate) if hasattr(pos_item, 'pnl_rate') else 0,
|
|
5612
5612
|
"product": product, # 상품 유형 (overseas_stock)
|
|
5613
|
+
"currency": pos_item.currency_code.strip().upper()
|
|
5614
|
+
if "currency_code" in pos_item.model_fields_set else None,
|
|
5613
5615
|
}
|
|
5614
5616
|
|
|
5615
5617
|
self._start_background_task(context,
|
|
@@ -5620,6 +5622,7 @@ class BrokerNodeExecutor(NodeExecutorBase):
|
|
|
5620
5622
|
current_prices=current_prices,
|
|
5621
5623
|
account_positions=account_positions if account_positions else None,
|
|
5622
5624
|
currency=pnl_info.currency if hasattr(pnl_info, 'currency') else "USD",
|
|
5625
|
+
account_valuation=tracker.get_valuation_snapshot(),
|
|
5623
5626
|
),
|
|
5624
5627
|
notification=True,
|
|
5625
5628
|
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Currency-scoped open workflow valuation, independent of realized trades."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import asdict, is_dataclass
|
|
4
|
+
from decimal import Decimal, InvalidOperation
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def workflow_valuation_snapshot(result, account_positions, observed_at, product):
|
|
9
|
+
if product != "overseas_stock" or not isinstance(account_positions, dict):
|
|
10
|
+
return None
|
|
11
|
+
positions = result.get("workflow_positions")
|
|
12
|
+
if not isinstance(positions, list):
|
|
13
|
+
return None
|
|
14
|
+
if positions and result.get("workflow_pnl_rate") is None:
|
|
15
|
+
return None
|
|
16
|
+
groups = {}
|
|
17
|
+
seen = set()
|
|
18
|
+
for item in positions:
|
|
19
|
+
row = asdict(item) if is_dataclass(item) else item
|
|
20
|
+
if not isinstance(row, dict):
|
|
21
|
+
return None
|
|
22
|
+
symbol = row.get("symbol")
|
|
23
|
+
account = account_positions.get(symbol)
|
|
24
|
+
if not isinstance(account, dict) or symbol in seen:
|
|
25
|
+
return None
|
|
26
|
+
seen.add(symbol)
|
|
27
|
+
currency = account.get("currency")
|
|
28
|
+
if not isinstance(currency, str) or not re.fullmatch(r"[A-Z]{3}", currency):
|
|
29
|
+
return None
|
|
30
|
+
values = {}
|
|
31
|
+
for key in ("quantity", "avg_price", "current_price", "pnl_amount"):
|
|
32
|
+
value = row.get(key)
|
|
33
|
+
if value is None or isinstance(value, bool):
|
|
34
|
+
return None
|
|
35
|
+
try:
|
|
36
|
+
values[key] = Decimal(str(value))
|
|
37
|
+
except InvalidOperation:
|
|
38
|
+
return None
|
|
39
|
+
if not values[key].is_finite() or (key != "pnl_amount" and values[key] <= 0):
|
|
40
|
+
return None
|
|
41
|
+
# Valuation is an estimate from the workflow's own retained cost basis.
|
|
42
|
+
pnl = values["pnl_amount"]
|
|
43
|
+
if abs(pnl - (values["current_price"] - values["avg_price"]) * values["quantity"]) > Decimal("0.0001"):
|
|
44
|
+
return None
|
|
45
|
+
group = groups.setdefault(currency, {"earned": Decimal(0), "lost": Decimal(0), "net": Decimal(0)})
|
|
46
|
+
group["earned"] += max(pnl, Decimal(0))
|
|
47
|
+
group["lost"] += max(-pnl, Decimal(0))
|
|
48
|
+
group["net"] = group["earned"] - group["lost"]
|
|
49
|
+
return {"version": 1, "product": product, "basis": "workflow_open_positions_gross",
|
|
50
|
+
"observed_at": observed_at.isoformat(),
|
|
51
|
+
"groups": [{"currency": currency, **group} for currency, group in sorted(groups.items())]}
|
|
@@ -5,7 +5,7 @@ authors = [
|
|
|
5
5
|
homepage = "https://programgarden.com"
|
|
6
6
|
requires-python = ">=3.12"
|
|
7
7
|
name = "programgarden"
|
|
8
|
-
version = "1.37.
|
|
8
|
+
version = "1.37.9"
|
|
9
9
|
license = "AGPL-3.0-or-later"
|
|
10
10
|
description = "ProgramGarden - 노드 기반 자동매매 DSL 실행 엔진"
|
|
11
11
|
readme = "README.md"
|
|
@@ -36,8 +36,8 @@ litellm = ">=1.40.0"
|
|
|
36
36
|
# 로 통째 실패한다(1.35.1 의 조용한 TypeError 보다 강한 모듈 로드 실패).
|
|
37
37
|
# (1.26.0 이후로도 context.py 는 WorkflowPnLEvent(**event_data) 에 personal_metrics
|
|
38
38
|
# 를 무조건 실으므로 그 하한 근거도 이 상한에 포함된다.)
|
|
39
|
-
programgarden-core = "^1.28.
|
|
40
|
-
programgarden-finance = "^1.9.
|
|
39
|
+
programgarden-core = "^1.28.2"
|
|
40
|
+
programgarden-finance = "^1.9.8"
|
|
41
41
|
programgarden-community = "^1.15.3"
|
|
42
42
|
|
|
43
43
|
[tool.poetry.group.dev.dependencies]
|
|
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.8 → programgarden-1.37.9}/programgarden/database/workflow_position_tracker.py
RENAMED
|
File without changes
|
{programgarden-1.37.8 → programgarden-1.37.9}/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
|