pfeed 0.0.1.dev1__tar.gz → 0.0.1.dev2__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.
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/LICENSE +1 -1
- pfeed-0.0.1.dev2/PKG-INFO +141 -0
- pfeed-0.0.1.dev2/README.md +107 -0
- pfeed-0.0.1.dev2/pfeed/__init__.py +16 -0
- pfeed-0.0.1.dev2/pfeed/cli/__init__.py +4 -0
- pfeed-0.0.1.dev2/pfeed/cli/commands/__init__.py +0 -0
- pfeed-0.0.1.dev2/pfeed/cli/commands/config.py +67 -0
- pfeed-0.0.1.dev2/pfeed/cli/commands/docker_compose.py +27 -0
- pfeed-0.0.1.dev2/pfeed/cli/commands/download.py +44 -0
- pfeed-0.0.1.dev2/pfeed/cli/commands/stream.py +0 -0
- pfeed-0.0.1.dev2/pfeed/cli/main.py +24 -0
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/config/logging.yml +1 -1
- pfeed-0.0.1.dev2/pfeed/config_handler.py +57 -0
- pfeed-0.0.1.dev2/pfeed/const/commons.py +6 -0
- pfeed-0.0.1.dev2/pfeed/const/paths.py +16 -0
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/datastore.py +2 -4
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/feeds/bybit_feed.py +5 -1
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/filepath.py +2 -2
- pfeed-0.0.1.dev2/pfeed/main.py +10 -0
- pfeed-0.0.1.dev2/pfeed/sources/bybit/__init__.py +2 -0
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/sources/bybit/const.py +2 -2
- pfeed-0.0.1.dev1/pfeed/sources/bybit/historical.py → pfeed-0.0.1.dev2/pfeed/sources/bybit/download.py +63 -59
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/sources/bybit/eda.ipynb +73 -1
- pfeed-0.0.1.dev2/pfeed/sources/bybit/stream.py +6 -0
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/utils/utils.py +6 -4
- pfeed-0.0.1.dev2/pfeed/utils/validate.py +30 -0
- pfeed-0.0.1.dev2/pyproject.toml +50 -0
- pfeed-0.0.1.dev1/PKG-INFO +0 -42
- pfeed-0.0.1.dev1/README.md +0 -17
- pfeed-0.0.1.dev1/pfeed/.DS_Store +0 -0
- pfeed-0.0.1.dev1/pfeed/__init__.py +0 -20
- pfeed-0.0.1.dev1/pfeed/const/__pycache__/__init__.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/const/__pycache__/commons.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/const/__pycache__/commons.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/const/__pycache__/paths.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/const/__pycache__/paths.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/const/commons.py +0 -2
- pfeed-0.0.1.dev1/pfeed/const/paths.py +0 -9
- pfeed-0.0.1.dev1/pfeed/feeds/__pycache__/__init__.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/feeds/__pycache__/__init__.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/feeds/__pycache__/base_feed.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/feeds/__pycache__/base_feed.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/feeds/__pycache__/bybit_feed.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/feeds/__pycache__/bybit_feed.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/feeds/__pycache__/yahoo_finance_feed.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/feeds/__pycache__/yahoo_finance_feed.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/main.py +0 -72
- pfeed-0.0.1.dev1/pfeed/sources/.DS_Store +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/__pycache__/__init__.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/__pycache__/__init__.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__init__.py +0 -2
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/__init__.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/__init__.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/api.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/api.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/bybit_feed.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/bytewax_temp.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/const.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/const.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/data_source.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/elt.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/etl.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/etl.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/historical.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/historical.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/streaming.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/__pycache__/streaming.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/sources/bybit/config.yml +0 -4
- pfeed-0.0.1.dev1/pfeed/utils/__pycache__/utils.cpython-310.pyc +0 -0
- pfeed-0.0.1.dev1/pfeed/utils/__pycache__/utils.cpython-311.pyc +0 -0
- pfeed-0.0.1.dev1/pyproject.toml +0 -33
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/feeds/__init__.py +0 -0
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/feeds/base_feed.py +0 -0
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/feeds/custom_csv_feed.py +0 -0
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/feeds/yahoo_finance_feed.py +0 -0
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/sources/__init__.py +0 -0
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/sources/bybit/api.py +0 -0
- {pfeed-0.0.1.dev1 → pfeed-0.0.1.dev2}/pfeed/sources/bybit/etl.py +0 -0
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright [
|
|
189
|
+
Copyright [2024] [Stephen Yau, PFund.ai]
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: pfeed
|
|
3
|
+
Version: 0.0.1.dev2
|
|
4
|
+
Summary: Data pipeline for algo-trading, getting and storing both real-time and historical data made easy.
|
|
5
|
+
Home-page: https://pfund.ai
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Keywords: trading,algo-trading,data pipeline,ETL,data lake,data warehouse,data integration,historical data,live data,data streaming
|
|
8
|
+
Author: Stephen Yau
|
|
9
|
+
Author-email: softwareentrepreneer+pfeed@gmail.com
|
|
10
|
+
Requires-Python: >=3.10,<4.0
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Requires-Dist: beautifulsoup4 (>=4.12.3,<5.0.0)
|
|
17
|
+
Requires-Dist: click (>=8.1.7,<9.0.0)
|
|
18
|
+
Requires-Dist: minio (>=7.2.3,<8.0.0)
|
|
19
|
+
Requires-Dist: orjson (>=3.9.12,<4.0.0)
|
|
20
|
+
Requires-Dist: pandas (>=2.2.0,<3.0.0)
|
|
21
|
+
Requires-Dist: pfund (>=0.0.1.dev2,<0.0.2)
|
|
22
|
+
Requires-Dist: platformdirs (>=4.2.0,<5.0.0)
|
|
23
|
+
Requires-Dist: pyarrow (>=15.0.0,<16.0.0)
|
|
24
|
+
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
25
|
+
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
|
|
26
|
+
Requires-Dist: ray (>=2.9.1,<3.0.0)
|
|
27
|
+
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
28
|
+
Requires-Dist: rich (>=13.7.0,<14.0.0)
|
|
29
|
+
Requires-Dist: tqdm (>=4.66.1,<5.0.0)
|
|
30
|
+
Requires-Dist: yfinance (>=0.2.36,<0.3.0)
|
|
31
|
+
Project-URL: Documentation, https://pfund.ai/docs
|
|
32
|
+
Project-URL: Repository, https://github.com/PFund-Software-Ltd/pfeed
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# PFeed: Data Pipeline for Algo-Trading, Getting and Storing Real-Time and Historical Data Made Easy.
|
|
36
|
+
|
|
37
|
+
[](https://python-poetry.org/)
|
|
38
|
+
[](https://pypi.org/project/pfeed)
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
PFeed (/piː fiːd/) is a data integration library tailored for algorithmic trading,
|
|
42
|
+
serving as an ETL (Extract, Transform, Load) data pipeline between raw data sources and traders,
|
|
43
|
+
helping them in creating a local data lake for quantitative research.
|
|
44
|
+
|
|
45
|
+
PFeed allows traders to download historical, paper, and live data from various data sources, both free and paid,
|
|
46
|
+
and stores them into a local data lake using [MinIO](https://min.io/).
|
|
47
|
+
|
|
48
|
+
It is designed to be used alongside [PFund](https://github.com/PFund-Software-Ltd/pfund) — A Complete Algo-Trading Framework for Machine Learning, TradFi, CeFi and DeFi ready. Supports Vectorized and Event-Driven Backtesting, Paper and Live Trading.
|
|
49
|
+
|
|
50
|
+
<details>
|
|
51
|
+
<summary>Table of Contents</summary>
|
|
52
|
+
|
|
53
|
+
- [Project Status](#project-status)
|
|
54
|
+
- [Mission](#mission)
|
|
55
|
+
- [Core Features](#core-features)
|
|
56
|
+
- [Installation](#installation)
|
|
57
|
+
- [Quick Start](#quick-start)
|
|
58
|
+
- [Download Historical Data on Command Line](#download-historical-data-on-command-line)
|
|
59
|
+
- [Download Historical Data in Python](#download-historical-data-in-python)
|
|
60
|
+
- [Supported Data Sources](#supported-data-sources)
|
|
61
|
+
- [Related Projects](#related-projects)
|
|
62
|
+
|
|
63
|
+
</details>
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
## Project Status
|
|
67
|
+
**_Caution: PFeed is at a VERY EARLY stage, use it at your own risk._**
|
|
68
|
+
|
|
69
|
+
PFeed is currently under active development, the framework design will be prioritized first over
|
|
70
|
+
stability and scalability.
|
|
71
|
+
|
|
72
|
+
Please note that the available version is a *dev* version, not a *stable* one. \
|
|
73
|
+
You are encouraged to play with the *dev* version, but only use it when a *stable* version is released.
|
|
74
|
+
|
|
75
|
+
> PFeed for the time being only supports [Bybit](https://bybit.com/) and Yahoo Finance for testing purpose.
|
|
76
|
+
|
|
77
|
+
## Mission
|
|
78
|
+
Algo-trading has always been a complicated task due to the multitude of components and procedures involved. \
|
|
79
|
+
Data collection and processing is probably the most mundane and yet critical part of it, as all results and findings
|
|
80
|
+
are derived from the data.
|
|
81
|
+
|
|
82
|
+
However, preparing this data for use is not quick and easy. For example, sometimes even when the data is available (e.g. [Bybit data](https://public.bybit.com/trading/)), it is often in raw form and requires some cleaning.
|
|
83
|
+
|
|
84
|
+
> PFeed's mission is to **_free traders from the tedious data work_** by providing cleaned data in a standard format that is ready for use, making them significantly faster to get to the analysis and strategy development phase.
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
## Core Features
|
|
88
|
+
- [x] Unified approach for interacting with various data sources, obtaining historical and real-time data
|
|
89
|
+
- [x] ETL data pipline for transforming raw data and storing it in [MinIO](https://min.io/) (optional)
|
|
90
|
+
- [x] Utilizes [Ray](https://github.com/ray-project/ray) for parallel data downloading
|
|
91
|
+
- [ ] Integrates with [Prefect](https://www.prefect.io) to control data flows
|
|
92
|
+
- [ ] Listens to PFund's trade engine and adds trade history to a local database [Timescaledb](https://www.timescale.com/) (optional)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
## Installation
|
|
96
|
+
### Using [Poetry](https://python-poetry.org) (Recommended)
|
|
97
|
+
> If you don't have poetry installed, please visit https://python-poetry.org/docs/
|
|
98
|
+
```bash
|
|
99
|
+
poetry add pfeed
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Using Pip
|
|
103
|
+
```bash
|
|
104
|
+
pip install pfeed
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
## Quick Start
|
|
109
|
+
### Download Historical Data on Command Line
|
|
110
|
+
```bash
|
|
111
|
+
pfeed download -s bybit -p BTC_USDT_PERP --no-minio
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Download Historical Data in Python
|
|
115
|
+
```python
|
|
116
|
+
from pfeed import bybit
|
|
117
|
+
bybit.download(pdts=['BTC_USDT_PERP'])
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
## Supported Data Sources
|
|
122
|
+
| Data Source | Get Historical Data | Download Historical Data | Get Live/Paper Data | Download Live/Paper Data |
|
|
123
|
+
| -------------------------------------------- | ------------------- | ------------------------ | ------------------- | ------------------------ |
|
|
124
|
+
| Yahoo Finance | 🟢 | ⚪ | ⚪ | ⚪ |
|
|
125
|
+
| Bybit | 🟢 | 🟢 | 🟡 | 🔴 |
|
|
126
|
+
| *Interactive Brokers (IB) | 🔴 | ⚪ | 🔴 | 🔴 |
|
|
127
|
+
| *[FirstRate Data](https://firstratedata.com) | 🔴 | 🔴 | ⚪ | ⚪ |
|
|
128
|
+
| Binance | 🔴 | 🔴 | 🔴 | 🔴 |
|
|
129
|
+
| OKX | 🔴 | 🔴 | 🔴 | 🔴 |
|
|
130
|
+
|
|
131
|
+
🟢 = finished \
|
|
132
|
+
🟡 = in progress \
|
|
133
|
+
🔴 = todo \
|
|
134
|
+
⚪ = not applicable \
|
|
135
|
+
\* = paid data \
|
|
136
|
+
get data = store it in memory for python to use \
|
|
137
|
+
download data = store it in local machine for later research
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
## Related Projects
|
|
141
|
+
- [PFund](https://github.com/PFund-Software-Ltd/pfund) — A Complete Algo-Trading Framework for Machine Learning, TradFi, CeFi and DeFi ready. Supports Vectorized and Event-Driven Backtesting, Paper and Live Trading
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# PFeed: Data Pipeline for Algo-Trading, Getting and Storing Real-Time and Historical Data Made Easy.
|
|
2
|
+
|
|
3
|
+
[](https://python-poetry.org/)
|
|
4
|
+
[](https://pypi.org/project/pfeed)
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
PFeed (/piː fiːd/) is a data integration library tailored for algorithmic trading,
|
|
8
|
+
serving as an ETL (Extract, Transform, Load) data pipeline between raw data sources and traders,
|
|
9
|
+
helping them in creating a local data lake for quantitative research.
|
|
10
|
+
|
|
11
|
+
PFeed allows traders to download historical, paper, and live data from various data sources, both free and paid,
|
|
12
|
+
and stores them into a local data lake using [MinIO](https://min.io/).
|
|
13
|
+
|
|
14
|
+
It is designed to be used alongside [PFund](https://github.com/PFund-Software-Ltd/pfund) — A Complete Algo-Trading Framework for Machine Learning, TradFi, CeFi and DeFi ready. Supports Vectorized and Event-Driven Backtesting, Paper and Live Trading.
|
|
15
|
+
|
|
16
|
+
<details>
|
|
17
|
+
<summary>Table of Contents</summary>
|
|
18
|
+
|
|
19
|
+
- [Project Status](#project-status)
|
|
20
|
+
- [Mission](#mission)
|
|
21
|
+
- [Core Features](#core-features)
|
|
22
|
+
- [Installation](#installation)
|
|
23
|
+
- [Quick Start](#quick-start)
|
|
24
|
+
- [Download Historical Data on Command Line](#download-historical-data-on-command-line)
|
|
25
|
+
- [Download Historical Data in Python](#download-historical-data-in-python)
|
|
26
|
+
- [Supported Data Sources](#supported-data-sources)
|
|
27
|
+
- [Related Projects](#related-projects)
|
|
28
|
+
|
|
29
|
+
</details>
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## Project Status
|
|
33
|
+
**_Caution: PFeed is at a VERY EARLY stage, use it at your own risk._**
|
|
34
|
+
|
|
35
|
+
PFeed is currently under active development, the framework design will be prioritized first over
|
|
36
|
+
stability and scalability.
|
|
37
|
+
|
|
38
|
+
Please note that the available version is a *dev* version, not a *stable* one. \
|
|
39
|
+
You are encouraged to play with the *dev* version, but only use it when a *stable* version is released.
|
|
40
|
+
|
|
41
|
+
> PFeed for the time being only supports [Bybit](https://bybit.com/) and Yahoo Finance for testing purpose.
|
|
42
|
+
|
|
43
|
+
## Mission
|
|
44
|
+
Algo-trading has always been a complicated task due to the multitude of components and procedures involved. \
|
|
45
|
+
Data collection and processing is probably the most mundane and yet critical part of it, as all results and findings
|
|
46
|
+
are derived from the data.
|
|
47
|
+
|
|
48
|
+
However, preparing this data for use is not quick and easy. For example, sometimes even when the data is available (e.g. [Bybit data](https://public.bybit.com/trading/)), it is often in raw form and requires some cleaning.
|
|
49
|
+
|
|
50
|
+
> PFeed's mission is to **_free traders from the tedious data work_** by providing cleaned data in a standard format that is ready for use, making them significantly faster to get to the analysis and strategy development phase.
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
## Core Features
|
|
54
|
+
- [x] Unified approach for interacting with various data sources, obtaining historical and real-time data
|
|
55
|
+
- [x] ETL data pipline for transforming raw data and storing it in [MinIO](https://min.io/) (optional)
|
|
56
|
+
- [x] Utilizes [Ray](https://github.com/ray-project/ray) for parallel data downloading
|
|
57
|
+
- [ ] Integrates with [Prefect](https://www.prefect.io) to control data flows
|
|
58
|
+
- [ ] Listens to PFund's trade engine and adds trade history to a local database [Timescaledb](https://www.timescale.com/) (optional)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
### Using [Poetry](https://python-poetry.org) (Recommended)
|
|
63
|
+
> If you don't have poetry installed, please visit https://python-poetry.org/docs/
|
|
64
|
+
```bash
|
|
65
|
+
poetry add pfeed
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Using Pip
|
|
69
|
+
```bash
|
|
70
|
+
pip install pfeed
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
### Download Historical Data on Command Line
|
|
76
|
+
```bash
|
|
77
|
+
pfeed download -s bybit -p BTC_USDT_PERP --no-minio
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Download Historical Data in Python
|
|
81
|
+
```python
|
|
82
|
+
from pfeed import bybit
|
|
83
|
+
bybit.download(pdts=['BTC_USDT_PERP'])
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
## Supported Data Sources
|
|
88
|
+
| Data Source | Get Historical Data | Download Historical Data | Get Live/Paper Data | Download Live/Paper Data |
|
|
89
|
+
| -------------------------------------------- | ------------------- | ------------------------ | ------------------- | ------------------------ |
|
|
90
|
+
| Yahoo Finance | 🟢 | ⚪ | ⚪ | ⚪ |
|
|
91
|
+
| Bybit | 🟢 | 🟢 | 🟡 | 🔴 |
|
|
92
|
+
| *Interactive Brokers (IB) | 🔴 | ⚪ | 🔴 | 🔴 |
|
|
93
|
+
| *[FirstRate Data](https://firstratedata.com) | 🔴 | 🔴 | ⚪ | ⚪ |
|
|
94
|
+
| Binance | 🔴 | 🔴 | 🔴 | 🔴 |
|
|
95
|
+
| OKX | 🔴 | 🔴 | 🔴 | 🔴 |
|
|
96
|
+
|
|
97
|
+
🟢 = finished \
|
|
98
|
+
🟡 = in progress \
|
|
99
|
+
🔴 = todo \
|
|
100
|
+
⚪ = not applicable \
|
|
101
|
+
\* = paid data \
|
|
102
|
+
get data = store it in memory for python to use \
|
|
103
|
+
download data = store it in local machine for later research
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
## Related Projects
|
|
107
|
+
- [PFund](https://github.com/PFund-Software-Ltd/pfund) — A Complete Algo-Trading Framework for Machine Learning, TradFi, CeFi and DeFi ready. Supports Vectorized and Event-Driven Backtesting, Paper and Live Trading
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from pfeed.config_handler import configure
|
|
2
|
+
from pfeed.sources import bybit
|
|
3
|
+
from pfeed.feeds import YahooFinanceFeed, BybitFeed
|
|
4
|
+
from importlib.metadata import version
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
__version__ = version('pfeed')
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__ = (
|
|
11
|
+
'__version__',
|
|
12
|
+
'configure',
|
|
13
|
+
'bybit',
|
|
14
|
+
'YahooFinanceFeed',
|
|
15
|
+
'BybitFeed',
|
|
16
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import yaml
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from pprint import pformat
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
from pfeed.const.paths import USER_CONFIG_FILE_PATH
|
|
10
|
+
from pfeed.config_handler import ConfigHandler
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def load_config(config_file_path: str | Path):
|
|
14
|
+
config_file_path = Path(config_file_path)
|
|
15
|
+
if config_file_path.is_file():
|
|
16
|
+
with open(config_file_path, 'r') as f:
|
|
17
|
+
return yaml.safe_load(f) or {}
|
|
18
|
+
return {}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def save_config(config: ConfigHandler, config_file_path: str | Path):
|
|
22
|
+
with open(config_file_path, 'w') as f:
|
|
23
|
+
yaml.dump(config.__dict__, f, default_flow_style=False)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def remove_config(config_file_path: str | Path):
|
|
27
|
+
config_file_path = Path(config_file_path)
|
|
28
|
+
if config_file_path.is_file():
|
|
29
|
+
os.remove(config_file_path)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@click.group(invoke_without_command=True)
|
|
33
|
+
@click.pass_context
|
|
34
|
+
@click.option('--data-path', type=click.Path(), help='Set the data path')
|
|
35
|
+
@click.option('--log-path', type=click.Path(), help='Set the log path')
|
|
36
|
+
@click.option('--logging-path', 'logging_config_file_path', type=click.Path(exists=True), help='Set the logging config file path')
|
|
37
|
+
@click.option('--logging-config', type=dict, help='Set the logging config')
|
|
38
|
+
@click.option('--use-fork-process', type=bool, help='If True, multiprocessing.set_start_method("fork")')
|
|
39
|
+
@click.option('--use-custom-excepthook', type=bool, help='If True, log uncaught exceptions to file')
|
|
40
|
+
def config(ctx, **kwargs):
|
|
41
|
+
"""Configures pfeed settings."""
|
|
42
|
+
# if theres command invoked after config (e.g. pfeed config reset), skip this
|
|
43
|
+
if ctx.invoked_subcommand:
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
config: ConfigHandler = ctx.obj['config']
|
|
47
|
+
|
|
48
|
+
# Filter out options that were not provided by the user
|
|
49
|
+
provided_options = {k: v for k, v in kwargs.items() if v is not None}
|
|
50
|
+
|
|
51
|
+
# prints out current config if no options are provided
|
|
52
|
+
if not provided_options:
|
|
53
|
+
click.echo(f"PFeed's config:\n{pformat(config.__dict__)}")
|
|
54
|
+
else:
|
|
55
|
+
for option, value in provided_options.items():
|
|
56
|
+
setattr(config, option, value)
|
|
57
|
+
click.echo(f"{option} set to: {value}")
|
|
58
|
+
|
|
59
|
+
save_config(config, USER_CONFIG_FILE_PATH)
|
|
60
|
+
click.echo(f"config saved to {USER_CONFIG_FILE_PATH}.")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@config.command()
|
|
64
|
+
def reset():
|
|
65
|
+
"""Resets the application configuration by removing the existing configuration file."""
|
|
66
|
+
remove_config(USER_CONFIG_FILE_PATH)
|
|
67
|
+
click.echo("Configuration successfully reset.")
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import importlib.resources
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
from dotenv import find_dotenv
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from pfeed.const.paths import PROJ_NAME
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.command(context_settings=dict(
|
|
12
|
+
ignore_unknown_options=True,
|
|
13
|
+
allow_extra_args=True,
|
|
14
|
+
))
|
|
15
|
+
@click.pass_context
|
|
16
|
+
def docker_compose(ctx):
|
|
17
|
+
"""Forwards commands to docker-compose with the package's docker-compose.yml file."""
|
|
18
|
+
package_dir = Path(importlib.resources.files(PROJ_NAME)).resolve().parents[0]
|
|
19
|
+
env_file_path = find_dotenv(usecwd=True, raise_error_if_not_found=True)
|
|
20
|
+
click.echo(f'env file: {env_file_path}')
|
|
21
|
+
docker_compose_file = package_dir / 'docker-compose.yml'
|
|
22
|
+
|
|
23
|
+
command = ['docker-compose', '-f', str(docker_compose_file)] + ctx.args
|
|
24
|
+
subprocess.run(command)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from pfeed.utils.validate import validate_pdts_and_ptypes
|
|
6
|
+
from pfeed.const.commons import ALIASES, SUPPORTED_DOWNLOAD_DATA_SOURCES, SUPPORTED_DATA_TYPES
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# add aliases to supported download data sources
|
|
10
|
+
SUPPORTED_DOWNLOAD_DATA_SOURCES_ALIASES_INCLUDED = SUPPORTED_DOWNLOAD_DATA_SOURCES + [k for k, v in ALIASES.items() if v in SUPPORTED_DOWNLOAD_DATA_SOURCES]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.command()
|
|
14
|
+
@click.pass_context
|
|
15
|
+
@click.option('-s', '--source', required=True, type=click.Choice(SUPPORTED_DOWNLOAD_DATA_SOURCES_ALIASES_INCLUDED, case_sensitive=False), help='Data source')
|
|
16
|
+
@click.option('-p', '--pdts', multiple=True, default=[], help='List of trading products')
|
|
17
|
+
@click.option('--dtypes', '--dt', multiple=True, type=click.Choice(SUPPORTED_DATA_TYPES, case_sensitive=False), help='List of data types, e.g. raw, tick, second, minute, hour, daily')
|
|
18
|
+
@click.option('--ptypes', '--pt', multiple=True, default=[], help='List of product types, e.g. PERP = get all perpetuals')
|
|
19
|
+
@click.option('-b', '--start-date', type=click.DateTime(formats=["%Y-%m-%d"]), help='Start date in YYYY-MM-DD format')
|
|
20
|
+
@click.option('-n', '--end-date', type=click.DateTime(formats=["%Y-%m-%d"]), help='End date in YYYY-MM-DD format')
|
|
21
|
+
@click.option('--batch-size', default=8, type=int, help='batch size for Ray tasks') # REVIEW
|
|
22
|
+
@click.option('--no-ray', is_flag=True)
|
|
23
|
+
@click.option('--no-minio', is_flag=True)
|
|
24
|
+
def download(ctx, source, pdts, dtypes, ptypes, start_date, end_date, batch_size, no_ray, no_minio):
|
|
25
|
+
if source in ALIASES:
|
|
26
|
+
source = ALIASES[source]
|
|
27
|
+
pdts = [pdt.replace('-', '_') for pdt in pdts]
|
|
28
|
+
validate_pdts_and_ptypes(source, pdts, ptypes, is_cli=True)
|
|
29
|
+
if start_date:
|
|
30
|
+
start_date = start_date.date()
|
|
31
|
+
if end_date:
|
|
32
|
+
end_date = end_date.date()
|
|
33
|
+
pipeline = importlib.import_module(f'pfeed.sources.{source.lower()}.download')
|
|
34
|
+
pipeline.run(
|
|
35
|
+
pdts=list(pdts),
|
|
36
|
+
dtypes=list(dtypes),
|
|
37
|
+
ptypes=list(ptypes),
|
|
38
|
+
start_date=start_date,
|
|
39
|
+
end_date=end_date,
|
|
40
|
+
batch_size=batch_size,
|
|
41
|
+
use_ray=not no_ray,
|
|
42
|
+
use_minio=not no_minio,
|
|
43
|
+
config=ctx.obj['config'],
|
|
44
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from pfeed.config_handler import ConfigHandler
|
|
4
|
+
from pfeed.const.paths import USER_CONFIG_FILE_PATH
|
|
5
|
+
from pfeed.cli.commands.docker_compose import docker_compose
|
|
6
|
+
from pfeed.cli.commands.config import config, load_config
|
|
7
|
+
from pfeed.cli.commands.download import download
|
|
8
|
+
# from pfeed.cli.commands.stream import stream
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.group(context_settings={"help_option_names": ["-h", "--help"]})
|
|
12
|
+
@click.pass_context
|
|
13
|
+
@click.version_option()
|
|
14
|
+
def pfeed_group(ctx):
|
|
15
|
+
"""PFeed's CLI"""
|
|
16
|
+
ctx.ensure_object(dict)
|
|
17
|
+
config: dict = load_config(USER_CONFIG_FILE_PATH)
|
|
18
|
+
ctx.obj['config'] = ConfigHandler(**config)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
pfeed_group.add_command(docker_compose)
|
|
22
|
+
pfeed_group.add_command(config)
|
|
23
|
+
pfeed_group.add_command(download)
|
|
24
|
+
# pfeed_group.add_command(stream)
|
|
@@ -27,7 +27,7 @@ handlers:
|
|
|
27
27
|
level: 'DEBUG'
|
|
28
28
|
formatter: 'file'
|
|
29
29
|
compressed_timed_rotating_file_handler:
|
|
30
|
-
class: 'pfund.
|
|
30
|
+
class: 'pfund.plogging.handlers.CompressedTimedRotatingFileHandler'
|
|
31
31
|
level: 'DEBUG'
|
|
32
32
|
formatter: 'file'
|
|
33
33
|
kwargs: {'when': 'midnight', 'backupCount': 7, 'utc': True, 'encoding': 'utf-8'}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import multiprocessing
|
|
4
|
+
import logging
|
|
5
|
+
from types import TracebackType
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
from pfeed.const.paths import PROJ_NAME, PROJ_CONFIG_PATH, LOG_PATH, DATA_PATH
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _custom_excepthook(exception_class: type[BaseException], exception: BaseException, traceback: TracebackType):
|
|
12
|
+
'''Catches any uncaught exceptions and logs them'''
|
|
13
|
+
# sys.__excepthook__(exception_class, exception, traceback)
|
|
14
|
+
try:
|
|
15
|
+
raise exception
|
|
16
|
+
except:
|
|
17
|
+
logging.getLogger(PROJ_NAME).exception('Uncaught exception:')
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class ConfigHandler:
|
|
22
|
+
data_path: str = str(DATA_PATH)
|
|
23
|
+
log_path: str = str(LOG_PATH)
|
|
24
|
+
logging_config_file_path: str = f'{PROJ_CONFIG_PATH}/logging.yml'
|
|
25
|
+
logging_config: dict | None = None
|
|
26
|
+
use_fork_process: bool = True
|
|
27
|
+
use_custom_excepthook: bool = True
|
|
28
|
+
|
|
29
|
+
def __post_init__(self):
|
|
30
|
+
for path in [self.data_path]:
|
|
31
|
+
if not os.path.exists(path):
|
|
32
|
+
os.makedirs(path)
|
|
33
|
+
print(f'created {path}')
|
|
34
|
+
|
|
35
|
+
if self.use_fork_process and sys.platform != 'win32':
|
|
36
|
+
multiprocessing.set_start_method('fork', force=True)
|
|
37
|
+
|
|
38
|
+
if self.use_custom_excepthook:
|
|
39
|
+
sys.excepthook = _custom_excepthook
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def configure(
|
|
43
|
+
data_path: str = str(DATA_PATH),
|
|
44
|
+
log_path: str = str(LOG_PATH),
|
|
45
|
+
logging_config_file_path: str = f'{PROJ_CONFIG_PATH}/logging.yml',
|
|
46
|
+
logging_config: dict | None=None,
|
|
47
|
+
use_fork_process: bool=True,
|
|
48
|
+
use_custom_excepthook: bool=True,
|
|
49
|
+
):
|
|
50
|
+
return ConfigHandler(
|
|
51
|
+
data_path=data_path,
|
|
52
|
+
log_path=log_path,
|
|
53
|
+
logging_config_file_path=logging_config_file_path,
|
|
54
|
+
logging_config=logging_config,
|
|
55
|
+
use_fork_process=use_fork_process,
|
|
56
|
+
use_custom_excepthook=use_custom_excepthook,
|
|
57
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from platformdirs import user_log_dir, user_data_dir, user_config_dir
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# project paths
|
|
6
|
+
PROJ_NAME = Path(__file__).resolve().parents[2].name
|
|
7
|
+
MAIN_PATH = Path(__file__).resolve().parents[3]
|
|
8
|
+
PROJ_PATH = MAIN_PATH / PROJ_NAME / PROJ_NAME
|
|
9
|
+
PROJ_CONFIG_PATH = PROJ_PATH / 'config'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# user paths
|
|
13
|
+
LOG_PATH = Path(user_log_dir()) / PROJ_NAME
|
|
14
|
+
DATA_PATH = Path(user_data_dir()) / PROJ_NAME
|
|
15
|
+
USER_CONFIG_PATH = Path(user_config_dir()) / PROJ_NAME
|
|
16
|
+
USER_CONFIG_FILE_PATH = USER_CONFIG_PATH / f'{PROJ_NAME}_config.yml'
|
|
@@ -7,8 +7,6 @@ from typing import Generator
|
|
|
7
7
|
from minio import Minio, S3Error
|
|
8
8
|
from minio.api import ObjectWriteResult
|
|
9
9
|
|
|
10
|
-
from pfeed.const.paths import PROJ_NAME
|
|
11
|
-
|
|
12
10
|
|
|
13
11
|
logger = logging.getLogger('minio')
|
|
14
12
|
|
|
@@ -16,11 +14,11 @@ logger = logging.getLogger('minio')
|
|
|
16
14
|
# EXTEND, currently only consider using MinIO
|
|
17
15
|
class Datastore:
|
|
18
16
|
DATA_PART_SIZE = 5 * (1024 ** 2) # part size for S3, 5 MB
|
|
19
|
-
BUCKET_NAME =
|
|
17
|
+
BUCKET_NAME = 'pfeed' + '-' + os.getenv('PFEED_ENV', 'DEV').lower()
|
|
20
18
|
|
|
21
19
|
def __init__(self, **kwargs):
|
|
22
20
|
self.minio = Minio(
|
|
23
|
-
endpoint=os.getenv('
|
|
21
|
+
endpoint=os.getenv('MINIO_HOST')+':'+os.getenv('MINIO_PORT', '9000'),
|
|
24
22
|
access_key=os.getenv('MINIO_ACCESS_KEY'),
|
|
25
23
|
secret_key=os.getenv('MINIO_SECRET_KEY'),
|
|
26
24
|
# turn off TLS, i.e. not using HTTPS
|
|
@@ -85,7 +85,11 @@ class BybitFeed(BaseFeed):
|
|
|
85
85
|
df = pd.read_parquet(io.BytesIO(resampled_data))
|
|
86
86
|
dfs.append(df)
|
|
87
87
|
return pd.concat(dfs)
|
|
88
|
-
|
|
88
|
+
|
|
89
|
+
# TODO?: maybe useful if used as a standalone program, not useful at all if used with PFund
|
|
90
|
+
def get_real_time_data(self, env='LIVE'):
|
|
91
|
+
pass
|
|
92
|
+
|
|
89
93
|
|
|
90
94
|
if __name__ == '__main__':
|
|
91
95
|
feed = BybitFeed()
|
|
@@ -25,9 +25,9 @@ class FilePath:
|
|
|
25
25
|
self.data_type = self.dtype = data_type.lower()
|
|
26
26
|
self.mode = mode
|
|
27
27
|
self.pdt = pdt.lower()
|
|
28
|
-
self.date = date
|
|
28
|
+
self.date = str(date)
|
|
29
29
|
self.file_extension = file_extension
|
|
30
|
-
self.filename = create_filename(pdt.upper(), date, file_extension)
|
|
30
|
+
self.filename = create_filename(pdt.upper(), self.date, file_extension)
|
|
31
31
|
self.storage_Path = self.sPath = Path(self.env) / self.data_source / self.mode / self.dtype / pdt.upper() / self.filename
|
|
32
32
|
self.storage_path = self.spath = str(self.storage_Path)
|
|
33
33
|
self.file_Path = self.fPath = self.data_Path / self.storage_Path
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
DATA_SOURCE = 'BYBIT'
|
|
2
2
|
# EXTEND: support FUT and IFUT
|
|
3
|
-
#
|
|
4
|
-
|
|
3
|
+
# SUPPORTED_PRODUCT_TYPES = ['SPOT', 'PERP', 'IPERP', 'FUT', 'IFUT']
|
|
4
|
+
SUPPORTED_PRODUCT_TYPES = ['SPOT', 'PERP', 'IPERP']
|
|
5
5
|
RAW_DATA_TYPE = 'tick'
|
|
6
6
|
# do not need to be precise
|
|
7
7
|
DATA_START_DATE = '2020-01-01'
|