signalflow-trading 0.2.1__py3-none-any.whl

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 (90) hide show
  1. signalflow/__init__.py +21 -0
  2. signalflow/analytics/__init__.py +0 -0
  3. signalflow/core/__init__.py +46 -0
  4. signalflow/core/base_mixin.py +232 -0
  5. signalflow/core/containers/__init__.py +21 -0
  6. signalflow/core/containers/order.py +216 -0
  7. signalflow/core/containers/portfolio.py +211 -0
  8. signalflow/core/containers/position.py +296 -0
  9. signalflow/core/containers/raw_data.py +167 -0
  10. signalflow/core/containers/raw_data_view.py +169 -0
  11. signalflow/core/containers/signals.py +198 -0
  12. signalflow/core/containers/strategy_state.py +147 -0
  13. signalflow/core/containers/trade.py +112 -0
  14. signalflow/core/decorators.py +103 -0
  15. signalflow/core/enums.py +270 -0
  16. signalflow/core/registry.py +322 -0
  17. signalflow/core/rolling_aggregator.py +362 -0
  18. signalflow/core/signal_transforms/__init__.py +5 -0
  19. signalflow/core/signal_transforms/base_signal_transform.py +186 -0
  20. signalflow/data/__init__.py +11 -0
  21. signalflow/data/raw_data_factory.py +225 -0
  22. signalflow/data/raw_store/__init__.py +7 -0
  23. signalflow/data/raw_store/base.py +271 -0
  24. signalflow/data/raw_store/duckdb_stores.py +696 -0
  25. signalflow/data/source/__init__.py +10 -0
  26. signalflow/data/source/base.py +300 -0
  27. signalflow/data/source/binance.py +442 -0
  28. signalflow/data/strategy_store/__init__.py +8 -0
  29. signalflow/data/strategy_store/base.py +278 -0
  30. signalflow/data/strategy_store/duckdb.py +409 -0
  31. signalflow/data/strategy_store/schema.py +36 -0
  32. signalflow/detector/__init__.py +7 -0
  33. signalflow/detector/adapter/__init__.py +5 -0
  34. signalflow/detector/adapter/pandas_detector.py +46 -0
  35. signalflow/detector/base.py +390 -0
  36. signalflow/detector/sma_cross.py +105 -0
  37. signalflow/feature/__init__.py +16 -0
  38. signalflow/feature/adapter/__init__.py +5 -0
  39. signalflow/feature/adapter/pandas_feature_extractor.py +54 -0
  40. signalflow/feature/base.py +330 -0
  41. signalflow/feature/feature_set.py +286 -0
  42. signalflow/feature/oscillator/__init__.py +5 -0
  43. signalflow/feature/oscillator/rsi_extractor.py +42 -0
  44. signalflow/feature/pandasta/__init__.py +10 -0
  45. signalflow/feature/pandasta/pandas_ta_extractor.py +141 -0
  46. signalflow/feature/pandasta/top_pandasta_extractors.py +64 -0
  47. signalflow/feature/smoother/__init__.py +5 -0
  48. signalflow/feature/smoother/sma_extractor.py +46 -0
  49. signalflow/strategy/__init__.py +9 -0
  50. signalflow/strategy/broker/__init__.py +15 -0
  51. signalflow/strategy/broker/backtest.py +172 -0
  52. signalflow/strategy/broker/base.py +186 -0
  53. signalflow/strategy/broker/executor/__init__.py +9 -0
  54. signalflow/strategy/broker/executor/base.py +35 -0
  55. signalflow/strategy/broker/executor/binance_spot.py +12 -0
  56. signalflow/strategy/broker/executor/virtual_spot.py +81 -0
  57. signalflow/strategy/broker/realtime_spot.py +12 -0
  58. signalflow/strategy/component/__init__.py +9 -0
  59. signalflow/strategy/component/base.py +65 -0
  60. signalflow/strategy/component/entry/__init__.py +7 -0
  61. signalflow/strategy/component/entry/fixed_size.py +57 -0
  62. signalflow/strategy/component/entry/signal.py +127 -0
  63. signalflow/strategy/component/exit/__init__.py +5 -0
  64. signalflow/strategy/component/exit/time_based.py +47 -0
  65. signalflow/strategy/component/exit/tp_sl.py +80 -0
  66. signalflow/strategy/component/metric/__init__.py +8 -0
  67. signalflow/strategy/component/metric/main_metrics.py +181 -0
  68. signalflow/strategy/runner/__init__.py +8 -0
  69. signalflow/strategy/runner/backtest_runner.py +208 -0
  70. signalflow/strategy/runner/base.py +19 -0
  71. signalflow/strategy/runner/optimized_backtest_runner.py +178 -0
  72. signalflow/strategy/runner/realtime_runner.py +0 -0
  73. signalflow/target/__init__.py +14 -0
  74. signalflow/target/adapter/__init__.py +5 -0
  75. signalflow/target/adapter/pandas_labeler.py +45 -0
  76. signalflow/target/base.py +409 -0
  77. signalflow/target/fixed_horizon_labeler.py +93 -0
  78. signalflow/target/static_triple_barrier.py +162 -0
  79. signalflow/target/triple_barrier.py +188 -0
  80. signalflow/utils/__init__.py +7 -0
  81. signalflow/utils/import_utils.py +11 -0
  82. signalflow/utils/tune_utils.py +19 -0
  83. signalflow/validator/__init__.py +6 -0
  84. signalflow/validator/base.py +139 -0
  85. signalflow/validator/sklearn_validator.py +527 -0
  86. signalflow_trading-0.2.1.dist-info/METADATA +149 -0
  87. signalflow_trading-0.2.1.dist-info/RECORD +90 -0
  88. signalflow_trading-0.2.1.dist-info/WHEEL +5 -0
  89. signalflow_trading-0.2.1.dist-info/licenses/LICENSE +21 -0
  90. signalflow_trading-0.2.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,300 @@
1
+ from abc import ABC, abstractmethod
2
+ from dataclasses import dataclass
3
+ from datetime import datetime
4
+ from typing import Optional, ClassVar
5
+ from signalflow.core import SfComponentType
6
+ import polars as pl
7
+
8
+ @dataclass
9
+ class RawDataSource(ABC):
10
+ """Abstract base class for raw data sources.
11
+
12
+ Defines the interface for data sources that provide market data
13
+ (exchanges, APIs, files, etc.). Sources are passive - they define
14
+ where data comes from but don't handle downloading.
15
+
16
+ RawDataSource is typically used in combination with RawDataLoader,
17
+ which handles the actual data retrieval and storage logic.
18
+
19
+ Key responsibilities:
20
+ - Define connection parameters (API keys, endpoints, etc.)
21
+ - Provide authentication credentials
22
+ - Specify data source configuration
23
+
24
+ Common implementations:
25
+ - Exchange APIs (Binance, Coinbase, etc.)
26
+ - Data providers (CryptoCompare, CoinGecko, etc.)
27
+ - File sources (CSV, Parquet, etc.)
28
+ - Database connections
29
+
30
+ Attributes:
31
+ component_type (ClassVar[SfComponentType]): Always RAW_DATA_SOURCE for registry.
32
+
33
+ Example:
34
+ ```python
35
+ from signalflow.core import sf_component, SfComponentType
36
+ from dataclasses import dataclass
37
+
38
+ @dataclass
39
+ @sf_component(name="binance_spot")
40
+ class BinanceSpotSource(RawDataSource):
41
+ '''Binance Spot API source'''
42
+ api_key: str = ""
43
+ api_secret: str = ""
44
+ base_url: str = "https://api.binance.com"
45
+
46
+ def get_client(self):
47
+ '''Create authenticated client'''
48
+ from binance.client import Client
49
+ return Client(self.api_key, self.api_secret)
50
+
51
+ # Use with loader
52
+ source = BinanceSpotSource(
53
+ api_key="your_key",
54
+ api_secret="your_secret"
55
+ )
56
+
57
+ loader = BinanceSpotLoader(
58
+ source=source,
59
+ store=store
60
+ )
61
+ ```
62
+
63
+ Example:
64
+ ```python
65
+ # File-based source
66
+ @dataclass
67
+ @sf_component(name="csv_source")
68
+ class CsvSource(RawDataSource):
69
+ '''CSV file source'''
70
+ file_path: Path
71
+ separator: str = ","
72
+
73
+ def read(self) -> pl.DataFrame:
74
+ return pl.read_csv(self.file_path, separator=self.separator)
75
+
76
+ # Database source
77
+ @dataclass
78
+ @sf_component(name="postgres_source")
79
+ class PostgresSource(RawDataSource):
80
+ '''PostgreSQL database source'''
81
+ host: str
82
+ port: int = 5432
83
+ database: str
84
+ user: str
85
+ password: str
86
+
87
+ def get_connection_string(self) -> str:
88
+ return f"postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.database}"
89
+ ```
90
+
91
+ Note:
92
+ Source classes are typically passive configuration containers.
93
+ Active data retrieval is handled by RawDataLoader implementations.
94
+ Use @sf_component decorator to register sources in the registry.
95
+
96
+ See Also:
97
+ RawDataLoader: Active component that uses sources to download data.
98
+ RawDataStore: Storage backend for persisting downloaded data.
99
+ """
100
+ component_type: ClassVar[SfComponentType] = SfComponentType.RAW_DATA_SOURCE
101
+
102
+
103
+ class RawDataLoader(ABC):
104
+ """Abstract base class for raw data loaders.
105
+
106
+ Defines the interface for loading market data from sources and
107
+ storing it in persistent storage. Loaders orchestrate the data
108
+ pipeline: source → transformation → storage.
109
+
110
+ Key responsibilities:
111
+ - Download data from sources (download)
112
+ - Sync/update existing data (sync)
113
+ - Handle rate limiting and retries
114
+ - Transform data to canonical format
115
+ - Store data in persistent backend
116
+
117
+ Typical workflow:
118
+ 1. Initial download: Fetch historical data
119
+ 2. Incremental sync: Update with latest data
120
+ 3. Gap filling: Detect and fill missing periods
121
+ 4. Validation: Ensure data quality and completeness
122
+
123
+ Attributes:
124
+ component_type (ClassVar[SfComponentType]): Always RAW_DATA_LOADER for registry.
125
+
126
+ Example:
127
+ ```python
128
+ from signalflow.core import sf_component, SfComponentType
129
+ from signalflow.data.raw_store import DuckDbSpotStore
130
+ from datetime import datetime
131
+
132
+ @sf_component(name="binance_spot_loader")
133
+ class BinanceSpotLoader(RawDataLoader):
134
+ '''Loads Binance spot data'''
135
+
136
+ def __init__(self, source: BinanceSpotSource, store: DuckDbSpotStore):
137
+ self.source = source
138
+ self.store = store
139
+ self.client = source.get_client()
140
+
141
+ def download(self, pairs: list[str], start: datetime, end: datetime):
142
+ '''Download historical data'''
143
+ for pair in pairs:
144
+ klines = self.client.get_historical_klines(
145
+ symbol=pair,
146
+ interval="1m",
147
+ start_str=start.isoformat(),
148
+ end_str=end.isoformat()
149
+ )
150
+
151
+ # Transform to canonical format
152
+ formatted = self._format_klines(klines)
153
+
154
+ # Store
155
+ self.store.insert_klines(pair, formatted)
156
+
157
+ def sync(self, pairs: list[str]):
158
+ '''Sync latest data'''
159
+ for pair in pairs:
160
+ # Get last timestamp
161
+ _, max_ts = self.store.get_time_bounds(pair)
162
+
163
+ if max_ts:
164
+ # Fetch data from max_ts to now
165
+ self.download(
166
+ pairs=[pair],
167
+ start=max_ts,
168
+ end=datetime.now()
169
+ )
170
+
171
+ def _format_klines(self, klines):
172
+ '''Transform to canonical format'''
173
+ return [
174
+ {
175
+ "timestamp": datetime.fromtimestamp(k[0] / 1000),
176
+ "open": float(k[1]),
177
+ "high": float(k[2]),
178
+ "low": float(k[3]),
179
+ "close": float(k[4]),
180
+ "volume": float(k[5]),
181
+ "trades": int(k[8])
182
+ }
183
+ for k in klines
184
+ ]
185
+
186
+ # Usage
187
+ source = BinanceSpotSource(api_key="key", api_secret="secret")
188
+ store = DuckDbSpotStore(Path("data/binance.duckdb"))
189
+ loader = BinanceSpotLoader(source=source, store=store)
190
+
191
+ # Initial download
192
+ loader.download(
193
+ pairs=["BTCUSDT", "ETHUSDT"],
194
+ start=datetime(2024, 1, 1),
195
+ end=datetime(2024, 12, 31)
196
+ )
197
+
198
+ # Daily sync
199
+ loader.sync(pairs=["BTCUSDT", "ETHUSDT"])
200
+ ```
201
+
202
+ Note:
203
+ Implementations should handle rate limiting and API errors gracefully.
204
+ sync() should be idempotent - safe to call multiple times.
205
+ Consider implementing gap detection and backfilling logic.
206
+
207
+ See Also:
208
+ RawDataSource: Defines where data comes from.
209
+ RawDataStore: Defines where data is stored.
210
+ RawDataFactory: Creates RawData from stored data.
211
+ """
212
+ component_type: ClassVar[SfComponentType] = SfComponentType.RAW_DATA_LOADER
213
+
214
+ @abstractmethod
215
+ def download(self, **kwargs):
216
+ """Download historical data from source to storage.
217
+
218
+ Initial data acquisition for a date range. Typically used for:
219
+ - First-time setup with historical data
220
+ - Backfilling large time periods
221
+ - Bulk data imports
222
+
223
+ Args:
224
+ **kwargs: Implementation-specific parameters. Common parameters:
225
+ - pairs (list[str]): Trading pairs to download
226
+ - start (datetime): Start datetime
227
+ - end (datetime): End datetime
228
+ - timeframe (str): Candlestick timeframe (e.g., "1m", "1h")
229
+
230
+ Example:
231
+ ```python
232
+ # Download historical data
233
+ loader.download(
234
+ pairs=["BTCUSDT", "ETHUSDT"],
235
+ start=datetime(2024, 1, 1),
236
+ end=datetime(2024, 12, 31),
237
+ timeframe="1m"
238
+ )
239
+
240
+ # Download with progress tracking
241
+ loader.download(
242
+ pairs=["BTCUSDT"],
243
+ start=datetime(2024, 1, 1),
244
+ end=datetime(2024, 1, 31),
245
+ batch_size=1000,
246
+ show_progress=True
247
+ )
248
+ ```
249
+
250
+ Note:
251
+ Should handle API rate limits with retries/delays.
252
+ Consider implementing chunking for large date ranges.
253
+ Validate data quality before storing.
254
+ """
255
+ pass
256
+
257
+ @abstractmethod
258
+ def sync(self, **kwargs):
259
+ """Sync/update existing data with latest data.
260
+
261
+ Incremental update for keeping data current. Typically used for:
262
+ - Daily/hourly updates
263
+ - Real-time data synchronization
264
+ - Gap filling
265
+
266
+ Implementation should:
267
+ - Detect last available timestamp per pair
268
+ - Fetch missing data from last timestamp to now
269
+ - Handle overlapping data (upsert)
270
+ - Be idempotent (safe to run multiple times)
271
+
272
+ Args:
273
+ **kwargs: Implementation-specific parameters. Common parameters:
274
+ - pairs (list[str]): Trading pairs to sync
275
+ - force (bool): Force full resync instead of incremental
276
+
277
+ Example:
278
+ ```python
279
+ # Incremental sync (fetch latest data)
280
+ loader.sync(pairs=["BTCUSDT", "ETHUSDT"])
281
+
282
+ # Force full resync
283
+ loader.sync(pairs=["BTCUSDT"], force=True)
284
+
285
+ # Scheduled sync (e.g., cron job)
286
+ import schedule
287
+
288
+ def daily_sync():
289
+ loader.sync(pairs=["BTCUSDT", "ETHUSDT"])
290
+ print(f"Synced at {datetime.now()}")
291
+
292
+ schedule.every().day.at("00:00").do(daily_sync)
293
+ ```
294
+
295
+ Note:
296
+ Should be idempotent - running multiple times is safe.
297
+ Consider checking for gaps and backfilling if needed.
298
+ Log sync status for monitoring.
299
+ """
300
+ pass