programgarden-core 1.31.0__tar.gz → 2.0.1__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_core-1.31.0 → programgarden_core-2.0.1}/PKG-INFO +3 -3
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/README.md +1 -1
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/expression/evaluator.py +23 -8
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/i18n/locales/en.json +0 -18
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/i18n/locales/ko.json +0 -18
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/credential.py +5 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/fundamental_stock.py +8 -5
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/pyproject.toml +3 -3
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/__init__.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/bases/__init__.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/bases/client.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/bases/components.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/bases/listener.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/bases/mixins.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/bases/products.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/bases/sql.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/bases/storage.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/code_node.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/exceptions.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/expression/__init__.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/i18n/__init__.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/i18n/translator.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/korea_alias.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/__init__.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/connection_rule.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/edge.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/event.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/exchange.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/field_binding.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/job.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/order_diagnostics.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/plugin_resource.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/resilience.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/resource.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/validation.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/workflow.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/__init__.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/account_futures.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/account_korea_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/account_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/ai.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/backtest.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/backtest_futures.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/backtest_korea_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/backtest_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/base.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/broker.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/calculation.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/code.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/condition.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/data.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/data_futures.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/data_korea_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/data_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/display.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/event.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/fundamental_korea_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/infra.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/market_external.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/market_status.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/open_orders_futures.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/open_orders_korea_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/open_orders_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/order.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/orderable_quantity_futures.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/portfolio.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/realtime_futures.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/realtime_korea_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/realtime_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/risk.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/session_gate.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/symbol.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/symbol_futures.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/symbol_korea_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/symbol_stock.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/trigger.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/presets/__init__.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/presets/news_analyst.json +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/presets/risk_manager.json +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/presets/strategist.json +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/presets/technical_analyst.json +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/registry/__init__.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/registry/credential_registry.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/registry/node_registry.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/registry/plugin_registry.py +0 -0
- {programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/retry_executor.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: programgarden-core
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: ProgramGarden Core - 노드 기반 DSL 핵심 타입 정의
|
|
5
5
|
License-Expression: AGPL-3.0-or-later
|
|
6
6
|
Author: 프로그램동산
|
|
@@ -10,7 +10,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.13
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
-
Requires-Dist: pydantic (>=2.0.
|
|
13
|
+
Requires-Dist: pydantic (>=2.0.1,<3.0.0)
|
|
14
14
|
Requires-Dist: tzdata (>=2025.2,<2026.0)
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
|
|
@@ -59,7 +59,7 @@ poetry add programgarden-core
|
|
|
59
59
|
| analysis | 2 | BacktestEngineNode, BenchmarkCompareNode |
|
|
60
60
|
| ai | 2 | LLMModelNode, AIAgentNode |
|
|
61
61
|
|
|
62
|
-
> Community adds
|
|
62
|
+
> Community adds four nodes: TelegramNode, FearGreedIndexNode, FileReaderNode and PerformanceReportNode, for 77 total.
|
|
63
63
|
|
|
64
64
|
## 사용 예시
|
|
65
65
|
|
|
@@ -43,7 +43,7 @@ poetry add programgarden-core
|
|
|
43
43
|
| analysis | 2 | BacktestEngineNode, BenchmarkCompareNode |
|
|
44
44
|
| ai | 2 | LLMModelNode, AIAgentNode |
|
|
45
45
|
|
|
46
|
-
> Community adds
|
|
46
|
+
> Community adds four nodes: TelegramNode, FearGreedIndexNode, FileReaderNode and PerformanceReportNode, for 77 total.
|
|
47
47
|
|
|
48
48
|
## 사용 예시
|
|
49
49
|
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/expression/evaluator.py
RENAMED
|
@@ -149,6 +149,21 @@ class DateNamespace:
|
|
|
149
149
|
'iso': '%Y-%m-%d',
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
def __init__(self, *, as_of: Optional[str] = None):
|
|
153
|
+
"""Optionally pin replay helpers to an explicit timezone-aware instant.
|
|
154
|
+
|
|
155
|
+
Live callers omit as_of and retain their existing local-clock behavior.
|
|
156
|
+
The execution host, never a model-supplied node setting, owns this clock.
|
|
157
|
+
"""
|
|
158
|
+
self._as_of = None
|
|
159
|
+
if as_of is not None:
|
|
160
|
+
self._as_of = datetime.fromisoformat(as_of.replace("Z", "+00:00"))
|
|
161
|
+
if self._as_of.tzinfo is None or self._as_of.utcoffset() is None:
|
|
162
|
+
raise ValueError("Replay as_of must include its timezone")
|
|
163
|
+
|
|
164
|
+
def _today(self) -> date:
|
|
165
|
+
return self._as_of.date() if self._as_of is not None else date.today()
|
|
166
|
+
|
|
152
167
|
def _format_date(self, d: date, fmt: Optional[str] = None) -> str:
|
|
153
168
|
"""날짜를 지정된 포맷으로 변환"""
|
|
154
169
|
if fmt is None:
|
|
@@ -159,40 +174,40 @@ class DateNamespace:
|
|
|
159
174
|
|
|
160
175
|
def today(self, format: Optional[str] = None) -> str:
|
|
161
176
|
"""오늘 날짜"""
|
|
162
|
-
return self._format_date(
|
|
177
|
+
return self._format_date(self._today(), format)
|
|
163
178
|
|
|
164
179
|
def now(self) -> str:
|
|
165
180
|
"""현재 시간 (ISO 형식)"""
|
|
166
|
-
return datetime.now().isoformat()[:19]
|
|
181
|
+
return self._as_of.isoformat(timespec="seconds") if self._as_of is not None else datetime.now().isoformat()[:19]
|
|
167
182
|
|
|
168
183
|
def ago(self, days: int, format: Optional[str] = None) -> str:
|
|
169
184
|
"""n일 전"""
|
|
170
|
-
d =
|
|
185
|
+
d = self._today() - timedelta(days=int(days))
|
|
171
186
|
return self._format_date(d, format)
|
|
172
187
|
|
|
173
188
|
def later(self, days: int, format: Optional[str] = None) -> str:
|
|
174
189
|
"""n일 후"""
|
|
175
|
-
d =
|
|
190
|
+
d = self._today() + timedelta(days=int(days))
|
|
176
191
|
return self._format_date(d, format)
|
|
177
192
|
|
|
178
193
|
def months_ago(self, months: int, format: Optional[str] = None) -> str:
|
|
179
194
|
"""n개월 전 (30일 기준)"""
|
|
180
|
-
d =
|
|
195
|
+
d = self._today() - timedelta(days=int(months) * 30)
|
|
181
196
|
return self._format_date(d, format)
|
|
182
197
|
|
|
183
198
|
def year_start(self, format: Optional[str] = None) -> str:
|
|
184
199
|
"""연초 (1월 1일)"""
|
|
185
|
-
d = date(
|
|
200
|
+
d = date(self._today().year, 1, 1)
|
|
186
201
|
return self._format_date(d, format)
|
|
187
202
|
|
|
188
203
|
def year_end(self, format: Optional[str] = None) -> str:
|
|
189
204
|
"""연말 (12월 31일)"""
|
|
190
|
-
d = date(
|
|
205
|
+
d = date(self._today().year, 12, 31)
|
|
191
206
|
return self._format_date(d, format)
|
|
192
207
|
|
|
193
208
|
def month_start(self, format: Optional[str] = None) -> str:
|
|
194
209
|
"""월초"""
|
|
195
|
-
d =
|
|
210
|
+
d = self._today().replace(day=1)
|
|
196
211
|
return self._format_date(d, format)
|
|
197
212
|
|
|
198
213
|
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/i18n/locales/en.json
RENAMED
|
@@ -64,8 +64,6 @@
|
|
|
64
64
|
"nodes.EventHandlerNode.name": "Event Handler",
|
|
65
65
|
"nodes.FearGreedIndexNode.description": "Fetches the CNN Fear & Greed Index, a market sentiment indicator ranging from 0 (Extreme Fear) to 100 (Extreme Greed). No broker connection or API key required. Outputs the current index value (0-100), label (Extreme Fear / Fear / Neutral / Greed / Extreme Greed), and previous day's close value. Built-in resilience with retry on API failures. Typical connection: FearGreedIndexNode → ConditionNode (for sentiment-based trading signals) or → SummaryDisplayNode.",
|
|
66
66
|
"nodes.FearGreedIndexNode.name": "Fear & Greed Index",
|
|
67
|
-
"nodes.FundamentalDataNode.description": "Fetches company financial data via Financial Modeling Prep (FMP) API. Supports four data types: company profile, income statement, balance sheet, and key metrics. Configure period (annual/quarter) and limit (number of periods to fetch). Requires FMP API credentials. Outputs financial data array and query summary. Typical connection: WatchlistNode → FundamentalDataNode → ConditionNode (for fundamental screening) or → TableDisplayNode.",
|
|
68
|
-
"nodes.FundamentalDataNode.name": "Fundamental Data (FMP)",
|
|
69
67
|
"nodes.PerformanceReportNode.name": "Performance Report (quantstats)",
|
|
70
68
|
"nodes.PerformanceReportNode.description": "Computes risk/return metrics (Sharpe, Sortino, max drawdown, CAGR, annualized volatility, Calmar) from an equity curve, price series, or return series using quantstats. Optionally computes beta and alpha against a benchmark series. Emits a drawdown time series and a formatted text report, and runs headless via the matplotlib Agg backend. Requires the optional 'perf' extra (pip install 'programgarden-community[perf]'); a missing or partially-installed extra raises a structured MissingDependencyError. Typical connection: BacktestEngineNode → PerformanceReportNode → TableDisplayNode.",
|
|
71
69
|
"nodes.FieldMappingNode.description": "Renames field names in data objects to a standard format. Use to normalize external API responses so downstream nodes can access data with consistent field names (e.g., rename 'adj_close' to 'close', 'vol' to 'volume'). Configure mappings as from/to pairs. Outputs mapped_data with renamed fields. Set preserve_unmapped=true to keep original fields alongside renamed ones. Note: this node only renames fields — it does not generate or transform data values. Typical connection: HTTPRequestNode → FieldMappingNode → ConditionNode.",
|
|
@@ -318,13 +316,6 @@
|
|
|
318
316
|
"fields.FileReaderNode.max_file_size_mb": "Maximum file size per file (MB). Range 1-50, default 10MB.",
|
|
319
317
|
"fields.FearGreedIndexNode.resilience": "Retry and fallback settings for API call failures",
|
|
320
318
|
"fields.FearGreedIndexNode.timeout_seconds": "API request timeout (seconds). Default 30s, adjust based on your network conditions.",
|
|
321
|
-
"fields.FundamentalDataNode.credential_id": "FMP API credentials. Register your API key from financialmodelingprep.com.",
|
|
322
|
-
"fields.FundamentalDataNode.symbols": "Symbols to query. [{symbol, exchange}] format.",
|
|
323
|
-
"fields.FundamentalDataNode.data_type": "Data type: profile, income_statement, balance_sheet, key_metrics",
|
|
324
|
-
"fields.FundamentalDataNode.period": "Period: annual or quarter. Used for financial statements and key metrics.",
|
|
325
|
-
"fields.FundamentalDataNode.limit": "Number of periods to fetch (most recent N). Default 1.",
|
|
326
|
-
"fields.FundamentalDataNode.timeout_seconds": "API request timeout (seconds). Default 30s.",
|
|
327
|
-
"fields.FundamentalDataNode.resilience": "Retry and fallback settings for API call failures",
|
|
328
319
|
"fields.PerformanceReportNode.data": "Input series: an array of numbers or of {date, <value_field>} objects (equity curve, price levels, or periodic returns).",
|
|
329
320
|
"fields.PerformanceReportNode.data_kind": "Kind of the input series: 'equity', 'prices', or 'returns'. Level series ('equity'/'prices') are converted to returns internally.",
|
|
330
321
|
"fields.PerformanceReportNode.value_field": "Key holding the numeric value when rows are objects (default 'close'; falls back to value/equity/return).",
|
|
@@ -655,13 +646,6 @@
|
|
|
655
646
|
"fieldNames.FileReaderNode.max_file_size_mb": "Max Size (MB)",
|
|
656
647
|
"fieldNames.FearGreedIndexNode.resilience": "Resilience",
|
|
657
648
|
"fieldNames.FearGreedIndexNode.timeout_seconds": "Timeout (sec)",
|
|
658
|
-
"fieldNames.FundamentalDataNode.credential_id": "FMP Credential",
|
|
659
|
-
"fieldNames.FundamentalDataNode.symbols": "Symbols",
|
|
660
|
-
"fieldNames.FundamentalDataNode.data_type": "Data Type",
|
|
661
|
-
"fieldNames.FundamentalDataNode.period": "Period",
|
|
662
|
-
"fieldNames.FundamentalDataNode.limit": "Limit",
|
|
663
|
-
"fieldNames.FundamentalDataNode.timeout_seconds": "Timeout (sec)",
|
|
664
|
-
"fieldNames.FundamentalDataNode.resilience": "Resilience",
|
|
665
649
|
"fieldNames.PerformanceReportNode.data": "Data Series",
|
|
666
650
|
"fieldNames.PerformanceReportNode.data_kind": "Data Kind",
|
|
667
651
|
"fieldNames.PerformanceReportNode.value_field": "Value Field",
|
|
@@ -886,8 +870,6 @@
|
|
|
886
870
|
"outputs.FearGreedIndexNode.label": "Index label (Extreme Fear / Fear / Neutral / Greed / Extreme Greed)",
|
|
887
871
|
"outputs.FearGreedIndexNode.previous_close": "Previous day's Fear & Greed Index value",
|
|
888
872
|
"outputs.FearGreedIndexNode.value": "Fear & Greed Index (0~100)",
|
|
889
|
-
"outputs.FundamentalDataNode.data": "Financial data array [{symbol, exchange, ...}]",
|
|
890
|
-
"outputs.FundamentalDataNode.summary": "Query summary {data_type, symbol_count, record_count}",
|
|
891
873
|
"outputs.PerformanceReportNode.metrics": "Metrics object {sharpe, sortino, max_drawdown, cagr, volatility, calmar[, beta, alpha]} (null on insufficient data).",
|
|
892
874
|
"outputs.PerformanceReportNode.report": "Formatted multi-line performance report text.",
|
|
893
875
|
"outputs.PerformanceReportNode.drawdown_series": "Drawdown time series as an array of {date, drawdown}.",
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/i18n/locales/ko.json
RENAMED
|
@@ -68,8 +68,6 @@
|
|
|
68
68
|
"nodes.FileReaderNode.name": "파일 리더",
|
|
69
69
|
"nodes.FearGreedIndexNode.description": "CNN 공포/탐욕 지수를 조회합니다. 0(극단적 공포)부터 100(극단적 탐욕)까지의 시장 심리 지표입니다. 브로커 연결이나 API 키가 필요 없습니다. 출력: 현재 지수값(0-100), 라벨(Extreme Fear / Fear / Neutral / Greed / Extreme Greed), 전일 종가. API 오류 시 자동 재시도 기능 내장. 일반적인 연결: FearGreedIndexNode → ConditionNode (심리 기반 매매 시그널) 또는 → SummaryDisplayNode.",
|
|
70
70
|
"nodes.FearGreedIndexNode.name": "공포/탐욕 지수",
|
|
71
|
-
"nodes.FundamentalDataNode.description": "Financial Modeling Prep (FMP) API로 기업 재무 데이터를 조회합니다. 4가지 데이터 유형: 기업 프로필, 손익계산서, 대차대조표, 핵심 지표. 기간(연간/분기)과 조회 수(최근 N기)를 설정합니다. FMP API 인증 정보 필요. 출력: 재무 데이터 배열, 조회 요약. 일반적인 연결: WatchlistNode → FundamentalDataNode → ConditionNode (펀더멘털 스크리닝) 또는 → TableDisplayNode.",
|
|
72
|
-
"nodes.FundamentalDataNode.name": "재무 데이터 (FMP)",
|
|
73
71
|
"nodes.PerformanceReportNode.name": "성과 리포트 (quantstats)",
|
|
74
72
|
"nodes.PerformanceReportNode.description": "자산곡선(equity)·가격·수익률 시계열로부터 quantstats 로 리스크·수익 지표(Sharpe, Sortino, 최대낙폭, CAGR, 연율 변동성, Calmar)를 산출합니다. 벤치마크 시계열을 지정하면 beta/alpha 를 추가로 계산합니다. 낙폭 시계열과 서식 리포트 텍스트를 출력하며, matplotlib Agg 백엔드로 헤드리스 동작합니다. 선택 'perf' extra 필요(pip install 'programgarden-community[perf]') — 미설치/부분설치 시 구조화된 MissingDependencyError 를 발생시킵니다. 대표 연결: BacktestEngineNode → PerformanceReportNode → TableDisplayNode.",
|
|
75
73
|
"nodes.HTTPRequestNode.description": "GET, POST, PUT, PATCH, DELETE를 지원하는 외부 REST API 호출 노드입니다. URL({{ }} 표현식 지원), 헤더, 쿼리 파라미터, JSON 요청 본문을 설정합니다. 인증 방식: Bearer 토큰, 헤더 키, 기본 인증, 쿼리 파라미터. 서버 에러(5xx), 속도 제한(429), 네트워크 장애 시 자동 재시도 기능 내장. 출력: 응답 데이터, HTTP 상태 코드, 응답 헤더, 응답 시간(ms). 실시간 데이터 소스 연결 시 ThrottleNode 필수. 일반적인 연결: ThrottleNode → HTTPRequestNode → FieldMappingNode. AI Agent 도구로 사용 가능.",
|
|
@@ -318,13 +316,6 @@
|
|
|
318
316
|
"fields.FileReaderNode.max_file_size_mb": "파일당 최대 크기 (MB). 1~50, 기본 10MB.",
|
|
319
317
|
"fields.FearGreedIndexNode.resilience": "API 호출 실패 시 재시도 및 폴백 설정",
|
|
320
318
|
"fields.FearGreedIndexNode.timeout_seconds": "API 요청 타임아웃 (초). 기본 30초, 네트워크 환경에 따라 조정하세요.",
|
|
321
|
-
"fields.FundamentalDataNode.credential_id": "FMP API 인증 정보. financialmodelingprep.com에서 발급받은 API 키를 등록하세요.",
|
|
322
|
-
"fields.FundamentalDataNode.symbols": "조회할 종목 목록. [{symbol, exchange}] 형식.",
|
|
323
|
-
"fields.FundamentalDataNode.data_type": "데이터 유형: profile(기업정보), income_statement(손익계산서), balance_sheet(대차대조표), key_metrics(핵심지표)",
|
|
324
|
-
"fields.FundamentalDataNode.period": "기간: annual(연간), quarter(분기). 재무제표/핵심지표 조회 시 사용.",
|
|
325
|
-
"fields.FundamentalDataNode.limit": "가져올 기간 수 (최근 N개). 기본 1.",
|
|
326
|
-
"fields.FundamentalDataNode.timeout_seconds": "API 요청 타임아웃 (초). 기본 30초.",
|
|
327
|
-
"fields.FundamentalDataNode.resilience": "API 호출 실패 시 재시도 및 폴백 설정",
|
|
328
319
|
"fields.PerformanceReportNode.data": "입력 시계열: 숫자 배열 또는 {date, <value_field>} 객체 배열(자산곡선/가격/수익률).",
|
|
329
320
|
"fields.PerformanceReportNode.data_kind": "입력 종류: 'equity'/'prices'/'returns'. 레벨 시계열('equity'/'prices')은 내부에서 수익률로 변환됩니다.",
|
|
330
321
|
"fields.PerformanceReportNode.value_field": "행이 객체일 때 숫자 값을 담은 키(기본 'close'; value/equity/return 폴백).",
|
|
@@ -655,13 +646,6 @@
|
|
|
655
646
|
"fieldNames.FileReaderNode.max_file_size_mb": "최대크기(MB)",
|
|
656
647
|
"fieldNames.FearGreedIndexNode.resilience": "재시도설정",
|
|
657
648
|
"fieldNames.FearGreedIndexNode.timeout_seconds": "타임아웃(초)",
|
|
658
|
-
"fieldNames.FundamentalDataNode.credential_id": "FMP 인증",
|
|
659
|
-
"fieldNames.FundamentalDataNode.symbols": "종목",
|
|
660
|
-
"fieldNames.FundamentalDataNode.data_type": "데이터유형",
|
|
661
|
-
"fieldNames.FundamentalDataNode.period": "기간",
|
|
662
|
-
"fieldNames.FundamentalDataNode.limit": "조회수",
|
|
663
|
-
"fieldNames.FundamentalDataNode.timeout_seconds": "타임아웃(초)",
|
|
664
|
-
"fieldNames.FundamentalDataNode.resilience": "재시도설정",
|
|
665
649
|
"fieldNames.PerformanceReportNode.data": "데이터 시계열",
|
|
666
650
|
"fieldNames.PerformanceReportNode.data_kind": "데이터 종류",
|
|
667
651
|
"fieldNames.PerformanceReportNode.value_field": "값 필드",
|
|
@@ -886,8 +870,6 @@
|
|
|
886
870
|
"outputs.FearGreedIndexNode.label": "지수 라벨 (Extreme Fear / Fear / Neutral / Greed / Extreme Greed)",
|
|
887
871
|
"outputs.FearGreedIndexNode.previous_close": "전일 공포/탐욕 지수",
|
|
888
872
|
"outputs.FearGreedIndexNode.value": "공포/탐욕 지수 (0~100)",
|
|
889
|
-
"outputs.FundamentalDataNode.data": "재무 데이터 배열 [{symbol, exchange, ...}]",
|
|
890
|
-
"outputs.FundamentalDataNode.summary": "조회 요약 {data_type, symbol_count, record_count}",
|
|
891
873
|
"outputs.PerformanceReportNode.metrics": "지표 객체 {sharpe, sortino, max_drawdown, cagr, volatility, calmar[, beta, alpha]} (데이터 부족 시 null).",
|
|
892
874
|
"outputs.PerformanceReportNode.report": "서식 성과 리포트 텍스트.",
|
|
893
875
|
"outputs.PerformanceReportNode.drawdown_series": "낙폭 시계열 [{date, drawdown}] 배열.",
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/credential.py
RENAMED
|
@@ -861,3 +861,8 @@ class DBCredential(BaseModel):
|
|
|
861
861
|
elif self.db_type == DBType.MYSQL:
|
|
862
862
|
return f"mysql://{self.username}:{self.password}@{self.host}:{self.port}/{self.database}"
|
|
863
863
|
raise ValueError(f"Unsupported db_type: {self.db_type}")
|
|
864
|
+
|
|
865
|
+
# Keep the published native "telegram" type readable while the platform uses telegram_bot.
|
|
866
|
+
BUILTIN_CREDENTIAL_SCHEMAS["telegram_bot"] = BUILTIN_CREDENTIAL_SCHEMAS["telegram"].model_copy(
|
|
867
|
+
update={"type_id": "telegram_bot"}
|
|
868
|
+
)
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/fundamental_stock.py
RENAMED
|
@@ -64,7 +64,7 @@ class OverseasStockFundamentalNode(BaseNode):
|
|
|
64
64
|
|
|
65
65
|
_usage: ClassVar[Dict[str, Any]] = {
|
|
66
66
|
"when_to_use": [
|
|
67
|
-
"Retrieve
|
|
67
|
+
"Retrieve LS security-detail data (PER, EPS, market cap, 52w high/low, industry) for a US-listed stock using the existing broker connection",
|
|
68
68
|
"Screen or rank stocks by fundamental criteria — pair with ConditionNode or FieldMappingNode for filtering",
|
|
69
69
|
"Give an AI Agent context about a stock's valuation alongside price data for investment thesis generation",
|
|
70
70
|
],
|
|
@@ -72,6 +72,7 @@ class OverseasStockFundamentalNode(BaseNode):
|
|
|
72
72
|
"For Korean domestic stock fundamentals — use KoreaStockFundamentalNode",
|
|
73
73
|
"When you only need price/volume data — use OverseasStockMarketDataNode",
|
|
74
74
|
"For real-time earnings or news events — fundamental data is updated daily, not tick-by-tick",
|
|
75
|
+
"For financial-statement history, free cash flow, ROE or PBR — these are not returned by this node; use a separately verified data source",
|
|
75
76
|
],
|
|
76
77
|
"typical_scenarios": [
|
|
77
78
|
"SplitNode.item → OverseasStockFundamentalNode → ConditionNode (filter by PER < 20)",
|
|
@@ -80,7 +81,8 @@ class OverseasStockFundamentalNode(BaseNode):
|
|
|
80
81
|
],
|
|
81
82
|
}
|
|
82
83
|
_features: ClassVar[List[str]] = [
|
|
83
|
-
"Returns per,
|
|
84
|
+
"Returns per, eps, market_cap, shares_outstanding, high_52w, low_52w and industry fields",
|
|
85
|
+
"Uses the LS overseas-stock broker credential; no separate financial-data subscription key is required",
|
|
84
86
|
"Item-based execution: pair with SplitNode to fetch fundamentals for each symbol in a universe",
|
|
85
87
|
"is_tool_enabled=True — AI Agent can call this node to analyze stock valuation autonomously",
|
|
86
88
|
"Broker connection is auto-injected via DAG traversal from OverseasStockBrokerNode",
|
|
@@ -130,7 +132,7 @@ class OverseasStockFundamentalNode(BaseNode):
|
|
|
130
132
|
}
|
|
131
133
|
],
|
|
132
134
|
},
|
|
133
|
-
"expected_output": "value port: {symbol, exchange, per,
|
|
135
|
+
"expected_output": "value port: {symbol, exchange, per, eps, market_cap, shares_outstanding, high_52w, low_52w, industry}.",
|
|
134
136
|
},
|
|
135
137
|
{
|
|
136
138
|
"title": "Fundamental screening — filter low-PER stocks",
|
|
@@ -172,7 +174,7 @@ class OverseasStockFundamentalNode(BaseNode):
|
|
|
172
174
|
"Supported exchanges: NYSE, NASDAQ, AMEX. Broker connection is auto-injected."
|
|
173
175
|
),
|
|
174
176
|
"output_consumption": (
|
|
175
|
-
"The `value` port emits: {symbol, exchange, per,
|
|
177
|
+
"The `value` port emits: {symbol, exchange, per, eps, market_cap, shares_outstanding, high_52w, low_52w, industry}. "
|
|
176
178
|
"Access individual fields via `{{ nodes.fundamental.value.per }}`."
|
|
177
179
|
),
|
|
178
180
|
"common_combinations": [
|
|
@@ -182,7 +184,8 @@ class OverseasStockFundamentalNode(BaseNode):
|
|
|
182
184
|
],
|
|
183
185
|
"pitfalls": [
|
|
184
186
|
"Fundamental data is updated daily — do not use it as a real-time signal",
|
|
185
|
-
"
|
|
187
|
+
"Missing broker fields can be empty or zero. For a positive-PER screen require a finite numeric per > 0 before comparing the upper bound; missing/zero/negative data must not create a buy signal",
|
|
188
|
+
"LS does not document the PER computation basis or the market-cap currency unit here. Do not claim TTM equivalence or compare cross-provider values without confirming the contract",
|
|
186
189
|
"The symbol field expects a single dict; use SplitNode for multi-symbol fundamental queries",
|
|
187
190
|
],
|
|
188
191
|
}
|
|
@@ -5,7 +5,7 @@ authors = [
|
|
|
5
5
|
homepage = "https://programgarden.com"
|
|
6
6
|
requires-python = ">=3.12"
|
|
7
7
|
name = "programgarden-core"
|
|
8
|
-
version = "
|
|
8
|
+
version = "2.0.1"
|
|
9
9
|
license = "AGPL-3.0-or-later"
|
|
10
10
|
description = "ProgramGarden Core - 노드 기반 DSL 핵심 타입 정의"
|
|
11
11
|
readme = "README.md"
|
|
@@ -16,7 +16,7 @@ packages = [
|
|
|
16
16
|
]
|
|
17
17
|
|
|
18
18
|
[tool.poetry.dependencies]
|
|
19
|
-
pydantic = ">=2.0.
|
|
19
|
+
pydantic = ">=2.0.1,<3.0.0"
|
|
20
20
|
tzdata = "^2025.2"
|
|
21
21
|
|
|
22
22
|
[tool.poetry.group.dev.dependencies]
|
|
@@ -26,5 +26,5 @@ mypy = "^1.0.0"
|
|
|
26
26
|
ruff = "^0.1.0"
|
|
27
27
|
|
|
28
28
|
[build-system]
|
|
29
|
-
requires = ["poetry-core>=2.0.
|
|
29
|
+
requires = ["poetry-core>=2.0.1,<3.0.0"]
|
|
30
30
|
build-backend = "poetry.core.masonry.api"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/bases/components.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
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/expression/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/i18n/translator.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/__init__.py
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/connection_rule.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/exchange.py
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/field_binding.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/plugin_resource.py
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/resilience.py
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/resource.py
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/validation.py
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/models/workflow.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/account_futures.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/account_stock.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/backtest_futures.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/backtest_stock.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/calculation.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/condition.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/data_futures.py
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/data_korea_stock.py
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/data_stock.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/market_external.py
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/market_status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/open_orders_stock.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/portfolio.py
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/realtime_futures.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/realtime_stock.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/session_gate.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/symbol_futures.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/nodes/symbol_stock.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/presets/__init__.py
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/presets/news_analyst.json
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/presets/risk_manager.json
RENAMED
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/presets/strategist.json
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/registry/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.31.0 → programgarden_core-2.0.1}/programgarden_core/registry/node_registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|