[ update ]: Cythonize Machine Learning Utilities
Browse files- .github/workflows/gru_pipeline.yaml +13 -4
- .github/workflows/lstm_gru_pipeline.yaml +13 -4
- .github/workflows/lstm_pipeline.yaml +13 -4
- Makefile +53 -2
- diagram/cryptocurrency_prediction.jpg +0 -0
- diagram/diagram.ai +0 -0
- postman/build/lib.linux-x86_64-3.10/json.cpython-310-x86_64-linux-gnu.so +0 -0
- postman/build/temp.linux-x86_64-3.10/json.o +0 -0
- converter.py → postman/converter.py +2 -2
- postman/json.c +1 -0
- postman/json.cpython-310-x86_64-linux-gnu.so +0 -0
- postman/json.pyx +1000 -0
- postman/setup.py +9 -0
- restful/utilities.py +0 -61
- training.py +0 -244
- training/build/lib.linux-x86_64-3.10/data_processor.cpython-310-x86_64-linux-gnu.so +0 -0
- training/build/lib.linux-x86_64-3.10/main.cpython-310-x86_64-linux-gnu.so +0 -0
- training/build/lib.linux-x86_64-3.10/model_builder.cpython-310-x86_64-linux-gnu.so +0 -0
- training/build/lib.linux-x86_64-3.10/post_processor.cpython-310-x86_64-linux-gnu.so +0 -0
- training/build/lib.linux-x86_64-3.10/trainer.cpython-310-x86_64-linux-gnu.so +0 -0
- training/build/temp.linux-x86_64-3.10/data_processor.o +0 -0
- training/build/temp.linux-x86_64-3.10/main.o +0 -0
- training/build/temp.linux-x86_64-3.10/model_builder.o +0 -0
- training/build/temp.linux-x86_64-3.10/post_processor.o +0 -0
- training/build/temp.linux-x86_64-3.10/trainer.o +0 -0
- training/data_processor.c +0 -0
- training/data_processor.cpython-310-x86_64-linux-gnu.so +0 -0
- training/data_processor.pyx +55 -0
- training/main.c +0 -0
- training/main.cpython-310-x86_64-linux-gnu.so +0 -0
- training/main.pyx +85 -0
- training/model_builder.c +0 -0
- training/model_builder.cpython-310-x86_64-linux-gnu.so +0 -0
- training/model_builder.pyx +74 -0
- training/post_processor.c +0 -0
- training/post_processor.cpython-310-x86_64-linux-gnu.so +0 -0
- training/post_processor.pyx +17 -0
- training/setup.py +24 -0
- training/trainer.c +0 -0
- training/trainer.cpython-310-x86_64-linux-gnu.so +0 -0
- training/trainer.pyx +31 -0
- trainingcli.py +30 -0
.github/workflows/gru_pipeline.yaml
CHANGED
@@ -127,6 +127,15 @@ jobs:
|
|
127 |
with:
|
128 |
name: datasets
|
129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
- name: Modeling and Training
|
131 |
# if: env.match != 'true'
|
132 |
run: |
|
@@ -136,7 +145,7 @@ jobs:
|
|
136 |
mkdir pickles
|
137 |
mkdir posttrained
|
138 |
|
139 |
-
python
|
140 |
--epochs=200 \
|
141 |
--batchs=32 \
|
142 |
--sequences=5 \
|
@@ -568,9 +577,9 @@ jobs:
|
|
568 |
sleep 60
|
569 |
chmod +x endpoints_test.sh && ./endpoints_test.sh
|
570 |
|
571 |
-
- name: Set Pipeline Schedule
|
572 |
-
|
573 |
-
|
574 |
|
575 |
# - name: Commit changes
|
576 |
# if: env.match != 'true'
|
|
|
127 |
with:
|
128 |
name: datasets
|
129 |
|
130 |
+
- name: Install Cython and Build ML Module
|
131 |
+
run: |
|
132 |
+
apt-get update && \
|
133 |
+
apt-get install -y gcc python3-dev gnupg
|
134 |
+
|
135 |
+
pip install cython
|
136 |
+
cd training && \
|
137 |
+
python setup.py build_ext --inplace && cd ..
|
138 |
+
|
139 |
- name: Modeling and Training
|
140 |
# if: env.match != 'true'
|
141 |
run: |
|
|
|
145 |
mkdir pickles
|
146 |
mkdir posttrained
|
147 |
|
148 |
+
python trainingcli.py \
|
149 |
--epochs=200 \
|
150 |
--batchs=32 \
|
151 |
--sequences=5 \
|
|
|
577 |
sleep 60
|
578 |
chmod +x endpoints_test.sh && ./endpoints_test.sh
|
579 |
|
580 |
+
# - name: Set Pipeline Schedule
|
581 |
+
# if: env.match != 'true'
|
582 |
+
# run: echo "$(date +'%Y-%m-%d')" > schedulers/gru_schedule.ctl
|
583 |
|
584 |
# - name: Commit changes
|
585 |
# if: env.match != 'true'
|
.github/workflows/lstm_gru_pipeline.yaml
CHANGED
@@ -127,6 +127,15 @@ jobs:
|
|
127 |
with:
|
128 |
name: datasets
|
129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
- name: Modeling and Training
|
131 |
# if: env.match != 'true'
|
132 |
run: |
|
@@ -136,15 +145,15 @@ jobs:
|
|
136 |
mkdir pickles
|
137 |
mkdir posttrained
|
138 |
|
139 |
-
python
|
140 |
--epochs=200 \
|
141 |
--batchs=32 \
|
142 |
--sequences=5 \
|
143 |
--algorithm=LSTM_GRU
|
144 |
|
145 |
-
- name: Set Pipeline Schedule
|
146 |
-
|
147 |
-
|
148 |
|
149 |
- name: Zip Posttrained, Models, and Pickles
|
150 |
# if: env.match != 'true'
|
|
|
127 |
with:
|
128 |
name: datasets
|
129 |
|
130 |
+
- name: Install Cython and Build ML Module
|
131 |
+
run: |
|
132 |
+
apt-get update && \
|
133 |
+
apt-get install -y gcc python3-dev gnupg
|
134 |
+
|
135 |
+
pip install cython
|
136 |
+
cd training && \
|
137 |
+
python setup.py build_ext --inplace && cd ..
|
138 |
+
|
139 |
- name: Modeling and Training
|
140 |
# if: env.match != 'true'
|
141 |
run: |
|
|
|
145 |
mkdir pickles
|
146 |
mkdir posttrained
|
147 |
|
148 |
+
python trainingcli.py \
|
149 |
--epochs=200 \
|
150 |
--batchs=32 \
|
151 |
--sequences=5 \
|
152 |
--algorithm=LSTM_GRU
|
153 |
|
154 |
+
# - name: Set Pipeline Schedule
|
155 |
+
# if: env.match != 'true'
|
156 |
+
# run: echo "$(date +'%Y-%m-%d')" > schedulers/lstm_gru_schedule.ctl
|
157 |
|
158 |
- name: Zip Posttrained, Models, and Pickles
|
159 |
# if: env.match != 'true'
|
.github/workflows/lstm_pipeline.yaml
CHANGED
@@ -126,6 +126,15 @@ jobs:
|
|
126 |
with:
|
127 |
name: datasets
|
128 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
- name: Modeling and Training
|
130 |
# if: env.match != 'true'
|
131 |
run: |
|
@@ -135,15 +144,15 @@ jobs:
|
|
135 |
mkdir pickles
|
136 |
mkdir posttrained
|
137 |
|
138 |
-
python
|
139 |
--epochs=200 \
|
140 |
--batchs=32 \
|
141 |
--sequences=5 \
|
142 |
--algorithm=LSTM
|
143 |
|
144 |
-
- name: Set Pipeline Schedule
|
145 |
-
|
146 |
-
|
147 |
|
148 |
- name: Zip Posttrained, Models, and Pickles
|
149 |
# if: env.match != 'true'
|
|
|
126 |
with:
|
127 |
name: datasets
|
128 |
|
129 |
+
- name: Install Cython and Build ML Module
|
130 |
+
run: |
|
131 |
+
apt-get update && \
|
132 |
+
apt-get install -y gcc python3-dev gnupg
|
133 |
+
|
134 |
+
pip install cython
|
135 |
+
cd training && \
|
136 |
+
python setup.py build_ext --inplace && cd ..
|
137 |
+
|
138 |
- name: Modeling and Training
|
139 |
# if: env.match != 'true'
|
140 |
run: |
|
|
|
144 |
mkdir pickles
|
145 |
mkdir posttrained
|
146 |
|
147 |
+
python trainingcli.py \
|
148 |
--epochs=200 \
|
149 |
--batchs=32 \
|
150 |
--sequences=5 \
|
151 |
--algorithm=LSTM
|
152 |
|
153 |
+
# - name: Set Pipeline Schedule
|
154 |
+
# if: env.match != 'true'
|
155 |
+
# run: echo "$(date +'%Y-%m-%d')" > schedulers/lstm_schedule.ctl
|
156 |
|
157 |
- name: Zip Posttrained, Models, and Pickles
|
158 |
# if: env.match != 'true'
|
Makefile
CHANGED
@@ -1,5 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
cutils:
|
2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
run:
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# makefile for building and running the application
|
2 |
+
|
3 |
+
.PHONY: all cutils ctrain cpostman converter run clean
|
4 |
+
|
5 |
+
# default target to build all components
|
6 |
+
all: cutils ctrain cpostman
|
7 |
+
|
8 |
+
# build Cython extensions in restful/cutils
|
9 |
cutils:
|
10 |
+
@echo "Building Cython extensions in restful/cutils..."
|
11 |
+
@cd restful/cutils && python setup.py build_ext --inplace
|
12 |
+
|
13 |
+
|
14 |
+
# build Cython extensions in training
|
15 |
+
ctrain:
|
16 |
+
@echo "Building Cython extensions in training..."
|
17 |
+
@cd training && python setup.py build_ext --inplace
|
18 |
+
|
19 |
+
|
20 |
+
# build Cython extensions in postman
|
21 |
+
cpostman:
|
22 |
+
@echo "Building Cython extensions in postman..."
|
23 |
+
@cd postman && python setup.py build_ext --inplace
|
24 |
|
25 |
+
|
26 |
+
# run the converter script
|
27 |
+
converter:
|
28 |
+
@echo "Running converter script..."
|
29 |
+
@python postman/converter.py
|
30 |
+
|
31 |
+
|
32 |
+
# run the application with uvicorn
|
33 |
run:
|
34 |
+
@echo "Starting the application..."
|
35 |
+
@uvicorn app:app --host 0.0.0.0 --port 7860 --reload
|
36 |
+
|
37 |
+
|
38 |
+
# clean up build artifacts
|
39 |
+
clean:
|
40 |
+
@echo "Cleaning up build artifacts..."
|
41 |
+
@find . -type f -name "*.so" -delete
|
42 |
+
@find . -type f -name "*.c" -delete
|
43 |
+
@find . -type f -name "*.cpp" -delete
|
44 |
+
@find . -type d -name "__pycache__" -exec rm -r {} +
|
45 |
+
|
46 |
+
|
47 |
+
# help message
|
48 |
+
help:
|
49 |
+
@echo "Usage:"
|
50 |
+
@echo " make all - Build all Cython extensions"
|
51 |
+
@echo " make cutils - Build Cython extensions in restful/cutils"
|
52 |
+
@echo " make ctrain - Build Cython extensions in training"
|
53 |
+
@echo " make cpostman - Build Cython extensions in postman"
|
54 |
+
@echo " make converter - Run the converter script"
|
55 |
+
@echo " make run - Start the application with Uvicorn"
|
56 |
+
@echo " make clean - Remove build artifacts"
|
diagram/cryptocurrency_prediction.jpg
CHANGED
diagram/diagram.ai
CHANGED
The diff for this file is too large to render.
See raw diff
|
|
postman/build/lib.linux-x86_64-3.10/json.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (380 kB). View file
|
|
postman/build/temp.linux-x86_64-3.10/json.o
ADDED
Binary file (688 kB). View file
|
|
converter.py → postman/converter.py
RENAMED
@@ -1,5 +1,6 @@
|
|
1 |
import json
|
2 |
|
|
|
3 |
class JSONProcessor:
|
4 |
def __init__(self, input_file: str, output_file: str) -> None:
|
5 |
self.input_file: str = input_file
|
@@ -30,5 +31,4 @@ def main():
|
|
30 |
symbols = processor.extract_symbols()
|
31 |
processor.save_json(symbols)
|
32 |
|
33 |
-
|
34 |
-
if __name__ == "__main__": main()
|
|
|
1 |
import json
|
2 |
|
3 |
+
# Json Processor
|
4 |
class JSONProcessor:
|
5 |
def __init__(self, input_file: str, output_file: str) -> None:
|
6 |
self.input_file: str = input_file
|
|
|
31 |
symbols = processor.extract_symbols()
|
32 |
processor.save_json(symbols)
|
33 |
|
34 |
+
if __name__ == "__main__": main()
|
|
postman/json.c
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
#error Do not use this file, it is the result of a failed Cython compilation.
|
postman/json.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (380 kB). View file
|
|
postman/json.pyx
ADDED
@@ -0,0 +1,1000 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from libc.stdlib cimport malloc, free
|
2 |
+
from cpython.pycapsule cimport PyCapsule_Import
|
3 |
+
from cpython.object cimport PyObject
|
4 |
+
from cpython.dict cimport PyDict_GetItemString
|
5 |
+
|
6 |
+
|
7 |
+
cdef class JSONProcessor:
|
8 |
+
cdef str input_file
|
9 |
+
cdef str output_file
|
10 |
+
cdef object data
|
11 |
+
|
12 |
+
def __init__(self, str input_file, str output_file):
|
13 |
+
self.input_file = input_file
|
14 |
+
self.output_file = output_file
|
15 |
+
self.data = None
|
16 |
+
|
17 |
+
cpdef void load_json(self):
|
18 |
+
import json
|
19 |
+
with open(self.input_file, 'r') as file:
|
20 |
+
self.data = json.load(file)
|
21 |
+
|
22 |
+
cpdef list extract_symbols(self):
|
23 |
+
if self.data is None:
|
24 |
+
raise ValueError("data not loaded. call load_json() first.")
|
25 |
+
quotes = self.data['finance']['result'][0]['quotes']
|
26 |
+
return [quote['symbol'] for quote in quotes]
|
27 |
+
|
28 |
+
cpdef void save_json(self, list data):
|
29 |
+
import json
|
30 |
+
with open(self.output_file, 'w') as file:
|
31 |
+
json.dump({'symbols': data}, file, indent=4)
|
32 |
+
print(f'saved: {self.output_file}')
|
33 |
+
|
34 |
+
|
35 |
+
""" --- """
|
36 |
+
""" --- """
|
37 |
+
""" --- """
|
38 |
+
""" --- """
|
39 |
+
""" --- """
|
40 |
+
""" --- """
|
41 |
+
""" --- """
|
42 |
+
""" --- """
|
43 |
+
""" --- """
|
44 |
+
""" --- """
|
45 |
+
""" --- """
|
46 |
+
""" --- """
|
47 |
+
""" --- """
|
48 |
+
""" --- """
|
49 |
+
""" --- """
|
50 |
+
""" --- """
|
51 |
+
""" --- """
|
52 |
+
""" --- """
|
53 |
+
""" --- """
|
54 |
+
""" --- """
|
55 |
+
""" --- """
|
56 |
+
""" --- """
|
57 |
+
""" --- """
|
58 |
+
""" --- """
|
59 |
+
""" --- """
|
60 |
+
""" --- """
|
61 |
+
""" --- """
|
62 |
+
""" --- """
|
63 |
+
""" --- """
|
64 |
+
""" --- """
|
65 |
+
""" --- """
|
66 |
+
""" --- """
|
67 |
+
""" --- """
|
68 |
+
""" --- """
|
69 |
+
""" --- """
|
70 |
+
""" --- """
|
71 |
+
""" --- """
|
72 |
+
""" --- """
|
73 |
+
""" --- """
|
74 |
+
""" --- """
|
75 |
+
""" --- """
|
76 |
+
""" --- """
|
77 |
+
""" --- """
|
78 |
+
""" --- """
|
79 |
+
""" --- """
|
80 |
+
""" --- """
|
81 |
+
""" --- """
|
82 |
+
""" --- """
|
83 |
+
""" --- """
|
84 |
+
""" --- """
|
85 |
+
""" --- """
|
86 |
+
""" --- """
|
87 |
+
""" --- """
|
88 |
+
""" --- """
|
89 |
+
""" --- """
|
90 |
+
""" --- """
|
91 |
+
""" --- """
|
92 |
+
""" --- """
|
93 |
+
""" --- """
|
94 |
+
""" --- """
|
95 |
+
""" --- """
|
96 |
+
""" --- """
|
97 |
+
""" --- """
|
98 |
+
""" --- """
|
99 |
+
""" --- """
|
100 |
+
""" --- """
|
101 |
+
""" --- """
|
102 |
+
""" --- """
|
103 |
+
""" --- """
|
104 |
+
""" --- """
|
105 |
+
""" --- """
|
106 |
+
""" --- """
|
107 |
+
""" --- """
|
108 |
+
""" --- """
|
109 |
+
""" --- """
|
110 |
+
""" --- """
|
111 |
+
""" --- """
|
112 |
+
""" --- """
|
113 |
+
""" --- """
|
114 |
+
""" --- """
|
115 |
+
""" --- """
|
116 |
+
""" --- """
|
117 |
+
""" --- """
|
118 |
+
""" --- """
|
119 |
+
""" --- """
|
120 |
+
""" --- """
|
121 |
+
""" --- """
|
122 |
+
""" --- """
|
123 |
+
""" --- """
|
124 |
+
""" --- """
|
125 |
+
""" --- """
|
126 |
+
""" --- """
|
127 |
+
""" --- """
|
128 |
+
""" --- """
|
129 |
+
""" --- """
|
130 |
+
""" --- """
|
131 |
+
""" --- """
|
132 |
+
""" --- """
|
133 |
+
""" --- """
|
134 |
+
""" --- """
|
135 |
+
""" --- """
|
136 |
+
""" --- """
|
137 |
+
""" --- """
|
138 |
+
""" --- """
|
139 |
+
""" --- """
|
140 |
+
""" --- """
|
141 |
+
""" --- """
|
142 |
+
""" --- """
|
143 |
+
""" --- """
|
144 |
+
""" --- """
|
145 |
+
""" --- """
|
146 |
+
""" --- """
|
147 |
+
""" --- """
|
148 |
+
""" --- """
|
149 |
+
""" --- """
|
150 |
+
""" --- """
|
151 |
+
""" --- """
|
152 |
+
""" --- """
|
153 |
+
""" --- """
|
154 |
+
""" --- """
|
155 |
+
""" --- """
|
156 |
+
""" --- """
|
157 |
+
""" --- """
|
158 |
+
""" --- """
|
159 |
+
""" --- """
|
160 |
+
""" --- """
|
161 |
+
""" --- """
|
162 |
+
""" --- """
|
163 |
+
""" --- """
|
164 |
+
""" --- """
|
165 |
+
""" --- """
|
166 |
+
""" --- """
|
167 |
+
""" --- """
|
168 |
+
""" --- """
|
169 |
+
""" --- """
|
170 |
+
""" --- """
|
171 |
+
""" --- """
|
172 |
+
""" --- """
|
173 |
+
""" --- """
|
174 |
+
""" --- """
|
175 |
+
""" --- """
|
176 |
+
""" --- """
|
177 |
+
""" --- """
|
178 |
+
""" --- """
|
179 |
+
""" --- """
|
180 |
+
""" --- """
|
181 |
+
""" --- """
|
182 |
+
""" --- """
|
183 |
+
""" --- """
|
184 |
+
""" --- """
|
185 |
+
""" --- """
|
186 |
+
""" --- """
|
187 |
+
""" --- """
|
188 |
+
""" --- """
|
189 |
+
""" --- """
|
190 |
+
""" --- """
|
191 |
+
""" --- """
|
192 |
+
""" --- """
|
193 |
+
""" --- """
|
194 |
+
""" --- """
|
195 |
+
""" --- """
|
196 |
+
""" --- """
|
197 |
+
""" --- """
|
198 |
+
""" --- """""" --- """
|
199 |
+
""" --- """
|
200 |
+
""" --- """
|
201 |
+
""" --- """
|
202 |
+
""" --- """
|
203 |
+
""" --- """
|
204 |
+
""" --- """
|
205 |
+
""" --- """
|
206 |
+
""" --- """
|
207 |
+
""" --- """
|
208 |
+
""" --- """
|
209 |
+
""" --- """
|
210 |
+
""" --- """
|
211 |
+
""" --- """
|
212 |
+
""" --- """
|
213 |
+
""" --- """
|
214 |
+
""" --- """
|
215 |
+
""" --- """
|
216 |
+
""" --- """
|
217 |
+
""" --- """
|
218 |
+
""" --- """
|
219 |
+
""" --- """
|
220 |
+
""" --- """
|
221 |
+
""" --- """
|
222 |
+
""" --- """
|
223 |
+
""" --- """
|
224 |
+
""" --- """
|
225 |
+
""" --- """
|
226 |
+
""" --- """
|
227 |
+
""" --- """
|
228 |
+
""" --- """
|
229 |
+
""" --- """
|
230 |
+
""" --- """
|
231 |
+
""" --- """
|
232 |
+
""" --- """
|
233 |
+
""" --- """
|
234 |
+
""" --- """
|
235 |
+
""" --- """
|
236 |
+
""" --- """
|
237 |
+
""" --- """
|
238 |
+
""" --- """
|
239 |
+
""" --- """
|
240 |
+
""" --- """
|
241 |
+
""" --- """
|
242 |
+
""" --- """
|
243 |
+
""" --- """
|
244 |
+
""" --- """
|
245 |
+
""" --- """
|
246 |
+
""" --- """
|
247 |
+
""" --- """
|
248 |
+
""" --- """
|
249 |
+
""" --- """
|
250 |
+
""" --- """
|
251 |
+
""" --- """
|
252 |
+
""" --- """
|
253 |
+
""" --- """
|
254 |
+
""" --- """
|
255 |
+
""" --- """
|
256 |
+
""" --- """
|
257 |
+
""" --- """
|
258 |
+
""" --- """
|
259 |
+
""" --- """
|
260 |
+
""" --- """
|
261 |
+
""" --- """
|
262 |
+
""" --- """
|
263 |
+
""" --- """
|
264 |
+
""" --- """
|
265 |
+
""" --- """
|
266 |
+
""" --- """
|
267 |
+
""" --- """
|
268 |
+
""" --- """
|
269 |
+
""" --- """
|
270 |
+
""" --- """
|
271 |
+
""" --- """
|
272 |
+
""" --- """
|
273 |
+
""" --- """
|
274 |
+
""" --- """
|
275 |
+
""" --- """
|
276 |
+
""" --- """
|
277 |
+
""" --- """
|
278 |
+
""" --- """
|
279 |
+
""" --- """
|
280 |
+
""" --- """
|
281 |
+
""" --- """
|
282 |
+
""" --- """
|
283 |
+
""" --- """
|
284 |
+
""" --- """
|
285 |
+
""" --- """
|
286 |
+
""" --- """
|
287 |
+
""" --- """
|
288 |
+
""" --- """
|
289 |
+
""" --- """
|
290 |
+
""" --- """
|
291 |
+
""" --- """
|
292 |
+
""" --- """
|
293 |
+
""" --- """
|
294 |
+
""" --- """
|
295 |
+
""" --- """
|
296 |
+
""" --- """
|
297 |
+
""" --- """
|
298 |
+
""" --- """
|
299 |
+
""" --- """
|
300 |
+
""" --- """
|
301 |
+
""" --- """
|
302 |
+
""" --- """
|
303 |
+
""" --- """
|
304 |
+
""" --- """
|
305 |
+
""" --- """
|
306 |
+
""" --- """
|
307 |
+
""" --- """
|
308 |
+
""" --- """
|
309 |
+
""" --- """
|
310 |
+
""" --- """
|
311 |
+
""" --- """
|
312 |
+
""" --- """
|
313 |
+
""" --- """
|
314 |
+
""" --- """
|
315 |
+
""" --- """
|
316 |
+
""" --- """
|
317 |
+
""" --- """
|
318 |
+
""" --- """
|
319 |
+
""" --- """
|
320 |
+
""" --- """
|
321 |
+
""" --- """
|
322 |
+
""" --- """
|
323 |
+
""" --- """
|
324 |
+
""" --- """
|
325 |
+
""" --- """
|
326 |
+
""" --- """
|
327 |
+
""" --- """
|
328 |
+
""" --- """
|
329 |
+
""" --- """
|
330 |
+
""" --- """
|
331 |
+
""" --- """
|
332 |
+
""" --- """
|
333 |
+
""" --- """
|
334 |
+
""" --- """
|
335 |
+
""" --- """
|
336 |
+
""" --- """
|
337 |
+
""" --- """
|
338 |
+
""" --- """
|
339 |
+
""" --- """
|
340 |
+
""" --- """
|
341 |
+
""" --- """
|
342 |
+
""" --- """
|
343 |
+
""" --- """
|
344 |
+
""" --- """
|
345 |
+
""" --- """
|
346 |
+
""" --- """
|
347 |
+
""" --- """
|
348 |
+
""" --- """
|
349 |
+
""" --- """
|
350 |
+
""" --- """
|
351 |
+
""" --- """
|
352 |
+
""" --- """
|
353 |
+
""" --- """
|
354 |
+
""" --- """
|
355 |
+
""" --- """
|
356 |
+
""" --- """
|
357 |
+
""" --- """
|
358 |
+
""" --- """
|
359 |
+
""" --- """
|
360 |
+
""" --- """
|
361 |
+
""" --- """
|
362 |
+
""" --- """
|
363 |
+
""" --- """
|
364 |
+
""" --- """
|
365 |
+
""" --- """
|
366 |
+
""" --- """
|
367 |
+
""" --- """
|
368 |
+
""" --- """
|
369 |
+
""" --- """
|
370 |
+
""" --- """
|
371 |
+
""" --- """
|
372 |
+
""" --- """
|
373 |
+
""" --- """
|
374 |
+
""" --- """
|
375 |
+
""" --- """
|
376 |
+
""" --- """
|
377 |
+
""" --- """
|
378 |
+
""" --- """
|
379 |
+
""" --- """
|
380 |
+
""" --- """
|
381 |
+
""" --- """
|
382 |
+
""" --- """
|
383 |
+
""" --- """
|
384 |
+
""" --- """
|
385 |
+
""" --- """
|
386 |
+
""" --- """
|
387 |
+
""" --- """
|
388 |
+
""" --- """
|
389 |
+
""" --- """
|
390 |
+
""" --- """
|
391 |
+
""" --- """
|
392 |
+
""" --- """
|
393 |
+
""" --- """
|
394 |
+
""" --- """
|
395 |
+
""" --- """
|
396 |
+
""" --- """
|
397 |
+
""" --- """
|
398 |
+
""" --- """
|
399 |
+
""" --- """
|
400 |
+
""" --- """
|
401 |
+
""" --- """
|
402 |
+
""" --- """
|
403 |
+
""" --- """
|
404 |
+
""" --- """
|
405 |
+
""" --- """
|
406 |
+
""" --- """
|
407 |
+
""" --- """
|
408 |
+
""" --- """
|
409 |
+
""" --- """
|
410 |
+
""" --- """
|
411 |
+
""" --- """
|
412 |
+
""" --- """
|
413 |
+
""" --- """
|
414 |
+
""" --- """
|
415 |
+
""" --- """
|
416 |
+
""" --- """
|
417 |
+
""" --- """
|
418 |
+
""" --- """
|
419 |
+
""" --- """
|
420 |
+
""" --- """
|
421 |
+
""" --- """
|
422 |
+
""" --- """
|
423 |
+
""" --- """
|
424 |
+
""" --- """
|
425 |
+
""" --- """
|
426 |
+
""" --- """
|
427 |
+
""" --- """
|
428 |
+
""" --- """
|
429 |
+
""" --- """
|
430 |
+
""" --- """
|
431 |
+
""" --- """
|
432 |
+
""" --- """
|
433 |
+
""" --- """
|
434 |
+
""" --- """
|
435 |
+
""" --- """
|
436 |
+
""" --- """
|
437 |
+
""" --- """
|
438 |
+
""" --- """
|
439 |
+
""" --- """
|
440 |
+
""" --- """
|
441 |
+
""" --- """
|
442 |
+
""" --- """
|
443 |
+
""" --- """
|
444 |
+
""" --- """
|
445 |
+
""" --- """
|
446 |
+
""" --- """
|
447 |
+
""" --- """
|
448 |
+
""" --- """
|
449 |
+
""" --- """
|
450 |
+
""" --- """
|
451 |
+
""" --- """
|
452 |
+
""" --- """
|
453 |
+
""" --- """
|
454 |
+
""" --- """
|
455 |
+
""" --- """
|
456 |
+
""" --- """
|
457 |
+
""" --- """
|
458 |
+
""" --- """
|
459 |
+
""" --- """
|
460 |
+
""" --- """
|
461 |
+
""" --- """
|
462 |
+
""" --- """
|
463 |
+
""" --- """
|
464 |
+
""" --- """
|
465 |
+
""" --- """
|
466 |
+
""" --- """
|
467 |
+
""" --- """
|
468 |
+
""" --- """
|
469 |
+
""" --- """
|
470 |
+
""" --- """
|
471 |
+
""" --- """
|
472 |
+
""" --- """
|
473 |
+
""" --- """
|
474 |
+
""" --- """
|
475 |
+
""" --- """
|
476 |
+
""" --- """
|
477 |
+
""" --- """
|
478 |
+
""" --- """
|
479 |
+
""" --- """
|
480 |
+
""" --- """
|
481 |
+
""" --- """
|
482 |
+
""" --- """
|
483 |
+
""" --- """
|
484 |
+
""" --- """
|
485 |
+
""" --- """
|
486 |
+
""" --- """
|
487 |
+
""" --- """
|
488 |
+
""" --- """
|
489 |
+
""" --- """
|
490 |
+
""" --- """
|
491 |
+
""" --- """
|
492 |
+
""" --- """
|
493 |
+
""" --- """
|
494 |
+
""" --- """
|
495 |
+
""" --- """
|
496 |
+
""" --- """
|
497 |
+
""" --- """
|
498 |
+
""" --- """
|
499 |
+
""" --- """
|
500 |
+
""" --- """
|
501 |
+
""" --- """
|
502 |
+
""" --- """
|
503 |
+
""" --- """
|
504 |
+
""" --- """
|
505 |
+
""" --- """
|
506 |
+
""" --- """
|
507 |
+
""" --- """
|
508 |
+
""" --- """
|
509 |
+
""" --- """
|
510 |
+
""" --- """
|
511 |
+
""" --- """
|
512 |
+
""" --- """
|
513 |
+
""" --- """
|
514 |
+
""" --- """
|
515 |
+
""" --- """
|
516 |
+
""" --- """
|
517 |
+
""" --- """
|
518 |
+
""" --- """
|
519 |
+
""" --- """
|
520 |
+
""" --- """
|
521 |
+
""" --- """
|
522 |
+
""" --- """
|
523 |
+
""" --- """
|
524 |
+
""" --- """
|
525 |
+
""" --- """""" --- """
|
526 |
+
""" --- """
|
527 |
+
""" --- """
|
528 |
+
""" --- """
|
529 |
+
""" --- """
|
530 |
+
""" --- """
|
531 |
+
""" --- """
|
532 |
+
""" --- """
|
533 |
+
""" --- """
|
534 |
+
""" --- """
|
535 |
+
""" --- """
|
536 |
+
""" --- """
|
537 |
+
""" --- """
|
538 |
+
""" --- """
|
539 |
+
""" --- """
|
540 |
+
""" --- """
|
541 |
+
""" --- """
|
542 |
+
""" --- """
|
543 |
+
""" --- """
|
544 |
+
""" --- """
|
545 |
+
""" --- """
|
546 |
+
""" --- """
|
547 |
+
""" --- """
|
548 |
+
""" --- """
|
549 |
+
""" --- """
|
550 |
+
""" --- """
|
551 |
+
""" --- """
|
552 |
+
""" --- """
|
553 |
+
""" --- """
|
554 |
+
""" --- """
|
555 |
+
""" --- """
|
556 |
+
""" --- """
|
557 |
+
""" --- """
|
558 |
+
""" --- """
|
559 |
+
""" --- """
|
560 |
+
""" --- """
|
561 |
+
""" --- """
|
562 |
+
""" --- """
|
563 |
+
""" --- """
|
564 |
+
""" --- """
|
565 |
+
""" --- """
|
566 |
+
""" --- """
|
567 |
+
""" --- """
|
568 |
+
""" --- """
|
569 |
+
""" --- """
|
570 |
+
""" --- """
|
571 |
+
""" --- """
|
572 |
+
""" --- """
|
573 |
+
""" --- """
|
574 |
+
""" --- """
|
575 |
+
""" --- """
|
576 |
+
""" --- """
|
577 |
+
""" --- """
|
578 |
+
""" --- """
|
579 |
+
""" --- """
|
580 |
+
""" --- """
|
581 |
+
""" --- """
|
582 |
+
""" --- """
|
583 |
+
""" --- """
|
584 |
+
""" --- """
|
585 |
+
""" --- """
|
586 |
+
""" --- """
|
587 |
+
""" --- """
|
588 |
+
""" --- """
|
589 |
+
""" --- """
|
590 |
+
""" --- """
|
591 |
+
""" --- """
|
592 |
+
""" --- """
|
593 |
+
""" --- """
|
594 |
+
""" --- """
|
595 |
+
""" --- """
|
596 |
+
""" --- """
|
597 |
+
""" --- """
|
598 |
+
""" --- """
|
599 |
+
""" --- """
|
600 |
+
""" --- """
|
601 |
+
""" --- """
|
602 |
+
""" --- """
|
603 |
+
""" --- """
|
604 |
+
""" --- """
|
605 |
+
""" --- """
|
606 |
+
""" --- """
|
607 |
+
""" --- """
|
608 |
+
""" --- """
|
609 |
+
""" --- """
|
610 |
+
""" --- """
|
611 |
+
""" --- """
|
612 |
+
""" --- """
|
613 |
+
""" --- """
|
614 |
+
""" --- """
|
615 |
+
""" --- """
|
616 |
+
""" --- """
|
617 |
+
""" --- """
|
618 |
+
""" --- """
|
619 |
+
""" --- """
|
620 |
+
""" --- """
|
621 |
+
""" --- """
|
622 |
+
""" --- """
|
623 |
+
""" --- """
|
624 |
+
""" --- """
|
625 |
+
""" --- """
|
626 |
+
""" --- """
|
627 |
+
""" --- """
|
628 |
+
""" --- """
|
629 |
+
""" --- """
|
630 |
+
""" --- """
|
631 |
+
""" --- """
|
632 |
+
""" --- """
|
633 |
+
""" --- """
|
634 |
+
""" --- """
|
635 |
+
""" --- """
|
636 |
+
""" --- """
|
637 |
+
""" --- """
|
638 |
+
""" --- """
|
639 |
+
""" --- """
|
640 |
+
""" --- """
|
641 |
+
""" --- """
|
642 |
+
""" --- """
|
643 |
+
""" --- """
|
644 |
+
""" --- """
|
645 |
+
""" --- """
|
646 |
+
""" --- """
|
647 |
+
""" --- """
|
648 |
+
""" --- """
|
649 |
+
""" --- """
|
650 |
+
""" --- """
|
651 |
+
""" --- """
|
652 |
+
""" --- """
|
653 |
+
""" --- """
|
654 |
+
""" --- """
|
655 |
+
""" --- """
|
656 |
+
""" --- """
|
657 |
+
""" --- """
|
658 |
+
""" --- """
|
659 |
+
""" --- """
|
660 |
+
""" --- """
|
661 |
+
""" --- """
|
662 |
+
""" --- """
|
663 |
+
""" --- """
|
664 |
+
""" --- """
|
665 |
+
""" --- """
|
666 |
+
""" --- """
|
667 |
+
""" --- """
|
668 |
+
""" --- """
|
669 |
+
""" --- """
|
670 |
+
""" --- """
|
671 |
+
""" --- """
|
672 |
+
""" --- """
|
673 |
+
""" --- """
|
674 |
+
""" --- """
|
675 |
+
""" --- """
|
676 |
+
""" --- """
|
677 |
+
""" --- """
|
678 |
+
""" --- """
|
679 |
+
""" --- """
|
680 |
+
""" --- """
|
681 |
+
""" --- """
|
682 |
+
""" --- """
|
683 |
+
""" --- """
|
684 |
+
""" --- """
|
685 |
+
""" --- """
|
686 |
+
""" --- """
|
687 |
+
""" --- """
|
688 |
+
""" --- """
|
689 |
+
""" --- """
|
690 |
+
""" --- """
|
691 |
+
""" --- """
|
692 |
+
""" --- """
|
693 |
+
""" --- """
|
694 |
+
""" --- """
|
695 |
+
""" --- """
|
696 |
+
""" --- """
|
697 |
+
""" --- """
|
698 |
+
""" --- """
|
699 |
+
""" --- """
|
700 |
+
""" --- """
|
701 |
+
""" --- """
|
702 |
+
""" --- """
|
703 |
+
""" --- """
|
704 |
+
""" --- """
|
705 |
+
""" --- """
|
706 |
+
""" --- """
|
707 |
+
""" --- """
|
708 |
+
""" --- """
|
709 |
+
""" --- """
|
710 |
+
""" --- """
|
711 |
+
""" --- """
|
712 |
+
""" --- """
|
713 |
+
""" --- """
|
714 |
+
""" --- """
|
715 |
+
""" --- """
|
716 |
+
""" --- """
|
717 |
+
""" --- """
|
718 |
+
""" --- """
|
719 |
+
""" --- """
|
720 |
+
""" --- """
|
721 |
+
""" --- """
|
722 |
+
""" --- """
|
723 |
+
""" --- """
|
724 |
+
""" --- """
|
725 |
+
""" --- """
|
726 |
+
""" --- """
|
727 |
+
""" --- """
|
728 |
+
""" --- """
|
729 |
+
""" --- """
|
730 |
+
""" --- """
|
731 |
+
""" --- """
|
732 |
+
""" --- """
|
733 |
+
""" --- """
|
734 |
+
""" --- """
|
735 |
+
""" --- """
|
736 |
+
""" --- """
|
737 |
+
""" --- """
|
738 |
+
""" --- """
|
739 |
+
""" --- """
|
740 |
+
""" --- """
|
741 |
+
""" --- """
|
742 |
+
""" --- """
|
743 |
+
""" --- """
|
744 |
+
""" --- """
|
745 |
+
""" --- """
|
746 |
+
""" --- """
|
747 |
+
""" --- """
|
748 |
+
""" --- """
|
749 |
+
""" --- """
|
750 |
+
""" --- """
|
751 |
+
""" --- """
|
752 |
+
""" --- """
|
753 |
+
""" --- """
|
754 |
+
""" --- """
|
755 |
+
""" --- """
|
756 |
+
""" --- """
|
757 |
+
""" --- """
|
758 |
+
""" --- """
|
759 |
+
""" --- """
|
760 |
+
""" --- """
|
761 |
+
""" --- """
|
762 |
+
""" --- """
|
763 |
+
""" --- """
|
764 |
+
""" --- """
|
765 |
+
""" --- """
|
766 |
+
""" --- """
|
767 |
+
""" --- """
|
768 |
+
""" --- """
|
769 |
+
""" --- """
|
770 |
+
""" --- """
|
771 |
+
""" --- """
|
772 |
+
""" --- """
|
773 |
+
""" --- """
|
774 |
+
""" --- """
|
775 |
+
""" --- """
|
776 |
+
""" --- """
|
777 |
+
""" --- """
|
778 |
+
""" --- """
|
779 |
+
""" --- """
|
780 |
+
""" --- """
|
781 |
+
""" --- """
|
782 |
+
""" --- """
|
783 |
+
""" --- """
|
784 |
+
""" --- """
|
785 |
+
""" --- """
|
786 |
+
""" --- """
|
787 |
+
""" --- """
|
788 |
+
""" --- """
|
789 |
+
""" --- """
|
790 |
+
""" --- """
|
791 |
+
""" --- """
|
792 |
+
""" --- """
|
793 |
+
""" --- """
|
794 |
+
""" --- """
|
795 |
+
""" --- """
|
796 |
+
""" --- """
|
797 |
+
""" --- """
|
798 |
+
""" --- """
|
799 |
+
""" --- """
|
800 |
+
""" --- """
|
801 |
+
""" --- """
|
802 |
+
""" --- """
|
803 |
+
""" --- """
|
804 |
+
""" --- """
|
805 |
+
""" --- """
|
806 |
+
""" --- """
|
807 |
+
""" --- """
|
808 |
+
""" --- """
|
809 |
+
""" --- """
|
810 |
+
""" --- """
|
811 |
+
""" --- """
|
812 |
+
""" --- """
|
813 |
+
""" --- """
|
814 |
+
""" --- """
|
815 |
+
""" --- """
|
816 |
+
""" --- """
|
817 |
+
""" --- """
|
818 |
+
""" --- """
|
819 |
+
""" --- """
|
820 |
+
""" --- """
|
821 |
+
""" --- """
|
822 |
+
""" --- """
|
823 |
+
""" --- """
|
824 |
+
""" --- """
|
825 |
+
""" --- """
|
826 |
+
""" --- """
|
827 |
+
""" --- """
|
828 |
+
""" --- """
|
829 |
+
""" --- """
|
830 |
+
""" --- """
|
831 |
+
""" --- """
|
832 |
+
""" --- """
|
833 |
+
""" --- """
|
834 |
+
""" --- """
|
835 |
+
""" --- """
|
836 |
+
""" --- """
|
837 |
+
""" --- """
|
838 |
+
""" --- """
|
839 |
+
""" --- """
|
840 |
+
""" --- """
|
841 |
+
""" --- """
|
842 |
+
""" --- """
|
843 |
+
""" --- """
|
844 |
+
""" --- """
|
845 |
+
""" --- """
|
846 |
+
""" --- """
|
847 |
+
""" --- """
|
848 |
+
""" --- """
|
849 |
+
""" --- """
|
850 |
+
""" --- """
|
851 |
+
""" --- """
|
852 |
+
""" --- """
|
853 |
+
""" --- """
|
854 |
+
""" --- """
|
855 |
+
""" --- """
|
856 |
+
""" --- """
|
857 |
+
""" --- """
|
858 |
+
""" --- """
|
859 |
+
""" --- """
|
860 |
+
""" --- """
|
861 |
+
""" --- """
|
862 |
+
""" --- """
|
863 |
+
""" --- """
|
864 |
+
""" --- """
|
865 |
+
""" --- """
|
866 |
+
""" --- """
|
867 |
+
""" --- """
|
868 |
+
""" --- """
|
869 |
+
""" --- """
|
870 |
+
""" --- """
|
871 |
+
""" --- """
|
872 |
+
""" --- """
|
873 |
+
""" --- """
|
874 |
+
""" --- """
|
875 |
+
""" --- """
|
876 |
+
""" --- """
|
877 |
+
""" --- """
|
878 |
+
""" --- """
|
879 |
+
""" --- """
|
880 |
+
""" --- """
|
881 |
+
""" --- """
|
882 |
+
""" --- """
|
883 |
+
""" --- """
|
884 |
+
""" --- """
|
885 |
+
""" --- """
|
886 |
+
""" --- """
|
887 |
+
""" --- """
|
888 |
+
""" --- """
|
889 |
+
""" --- """
|
890 |
+
""" --- """
|
891 |
+
""" --- """
|
892 |
+
""" --- """
|
893 |
+
""" --- """
|
894 |
+
""" --- """
|
895 |
+
""" --- """
|
896 |
+
""" --- """
|
897 |
+
""" --- """
|
898 |
+
""" --- """
|
899 |
+
""" --- """
|
900 |
+
""" --- """
|
901 |
+
""" --- """
|
902 |
+
""" --- """
|
903 |
+
""" --- """
|
904 |
+
""" --- """
|
905 |
+
""" --- """
|
906 |
+
""" --- """
|
907 |
+
""" --- """
|
908 |
+
""" --- """
|
909 |
+
""" --- """
|
910 |
+
""" --- """
|
911 |
+
""" --- """
|
912 |
+
""" --- """
|
913 |
+
""" --- """
|
914 |
+
""" --- """
|
915 |
+
""" --- """
|
916 |
+
""" --- """
|
917 |
+
""" --- """
|
918 |
+
""" --- """
|
919 |
+
""" --- """
|
920 |
+
""" --- """
|
921 |
+
""" --- """
|
922 |
+
""" --- """
|
923 |
+
""" --- """
|
924 |
+
""" --- """
|
925 |
+
""" --- """
|
926 |
+
""" --- """
|
927 |
+
""" --- """
|
928 |
+
""" --- """
|
929 |
+
""" --- """
|
930 |
+
""" --- """
|
931 |
+
""" --- """
|
932 |
+
""" --- """
|
933 |
+
""" --- """
|
934 |
+
""" --- """
|
935 |
+
""" --- """
|
936 |
+
""" --- """
|
937 |
+
""" --- """
|
938 |
+
""" --- """
|
939 |
+
""" --- """
|
940 |
+
""" --- """
|
941 |
+
""" --- """
|
942 |
+
""" --- """
|
943 |
+
""" --- """
|
944 |
+
""" --- """
|
945 |
+
""" --- """
|
946 |
+
""" --- """
|
947 |
+
""" --- """
|
948 |
+
""" --- """
|
949 |
+
""" --- """
|
950 |
+
""" --- """
|
951 |
+
""" --- """
|
952 |
+
""" --- """
|
953 |
+
""" --- """
|
954 |
+
""" --- """
|
955 |
+
""" --- """
|
956 |
+
""" --- """
|
957 |
+
""" --- """
|
958 |
+
""" --- """
|
959 |
+
""" --- """
|
960 |
+
""" --- """
|
961 |
+
""" --- """
|
962 |
+
""" --- """
|
963 |
+
""" --- """
|
964 |
+
""" --- """
|
965 |
+
""" --- """
|
966 |
+
""" --- """
|
967 |
+
""" --- """
|
968 |
+
""" --- """
|
969 |
+
""" --- """
|
970 |
+
""" --- """
|
971 |
+
""" --- """
|
972 |
+
""" --- """
|
973 |
+
""" --- """
|
974 |
+
""" --- """
|
975 |
+
""" --- """
|
976 |
+
""" --- """
|
977 |
+
""" --- """
|
978 |
+
""" --- """
|
979 |
+
""" --- """
|
980 |
+
""" --- """
|
981 |
+
""" --- """
|
982 |
+
""" --- """
|
983 |
+
""" --- """
|
984 |
+
""" --- """
|
985 |
+
""" --- """
|
986 |
+
""" --- """
|
987 |
+
""" --- """
|
988 |
+
""" --- """
|
989 |
+
""" --- """
|
990 |
+
""" --- """
|
991 |
+
""" --- """
|
992 |
+
""" --- """
|
993 |
+
""" --- """
|
994 |
+
""" --- """
|
995 |
+
""" --- """
|
996 |
+
""" --- """
|
997 |
+
""" --- """
|
998 |
+
""" --- """
|
999 |
+
""" --- """
|
1000 |
+
""" --- """
|
postman/setup.py
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from setuptools import setup
|
2 |
+
from Cython.Build import cythonize
|
3 |
+
|
4 |
+
setup(
|
5 |
+
ext_modules = cythonize(
|
6 |
+
"json.pyx",
|
7 |
+
compiler_directives = {'language_level': "3"}
|
8 |
+
),
|
9 |
+
)
|
restful/utilities.py
DELETED
@@ -1,61 +0,0 @@
|
|
1 |
-
import os
|
2 |
-
from joblib import load
|
3 |
-
from numpy import append, expand_dims
|
4 |
-
from pandas import read_json, to_datetime, Timedelta
|
5 |
-
|
6 |
-
from tensorflow.keras.models import load_model
|
7 |
-
|
8 |
-
|
9 |
-
class Utilities:
|
10 |
-
def __init__(self) -> None:
|
11 |
-
self.model_path = './models'
|
12 |
-
self.posttrained_path = './posttrained'
|
13 |
-
self.scaler_path = './pickles'
|
14 |
-
|
15 |
-
async def cryptocurrency_prediction_utils(self,
|
16 |
-
days: int, sequence_length: int, model_name: str) -> tuple:
|
17 |
-
model_path = os.path.join(self.model_path, f'{model_name}.keras')
|
18 |
-
model = load_model(model_path)
|
19 |
-
|
20 |
-
dataframe_path = os.path.join(self.posttrained_path, f'{model_name}-posttrained.json')
|
21 |
-
dataframe = read_json(dataframe_path)
|
22 |
-
dataframe.set_index('Date', inplace = True)
|
23 |
-
|
24 |
-
minmax_scaler = load(os.path.join(self.scaler_path, f'{model_name}_minmax_scaler.pickle'))
|
25 |
-
standard_scaler = load(os.path.join(self.scaler_path, f'{model_name}_standard_scaler.pickle'))
|
26 |
-
|
27 |
-
lst_seq = dataframe[-sequence_length:].values
|
28 |
-
lst_seq = expand_dims(lst_seq, axis = 0)
|
29 |
-
|
30 |
-
# Predicted
|
31 |
-
predicted_prices = {}
|
32 |
-
last_date = to_datetime(dataframe.index[-1])
|
33 |
-
|
34 |
-
for _ in range(days):
|
35 |
-
predicted_price = model.predict(lst_seq)
|
36 |
-
last_date = last_date + Timedelta(days = 1)
|
37 |
-
|
38 |
-
predicted_prices[last_date] = minmax_scaler.inverse_transform(predicted_price)
|
39 |
-
predicted_prices[last_date] = standard_scaler.inverse_transform(predicted_prices[last_date])
|
40 |
-
|
41 |
-
lst_seq = append(lst_seq[:, 1:, :], [predicted_price], axis = 1)
|
42 |
-
|
43 |
-
predictions = [
|
44 |
-
{'date': date.strftime('%Y-%m-%d'), 'price': float(price)} \
|
45 |
-
for date, price in predicted_prices.items()
|
46 |
-
]
|
47 |
-
|
48 |
-
# Actual
|
49 |
-
df_date = dataframe.index[-sequence_length:].values
|
50 |
-
df_date = [to_datetime(date) for date in df_date]
|
51 |
-
|
52 |
-
dataframe[['Close']] = minmax_scaler.inverse_transform(dataframe)
|
53 |
-
dataframe[['Close']] = standard_scaler.inverse_transform(dataframe)
|
54 |
-
df_close = dataframe.iloc[-sequence_length:]['Close'].values
|
55 |
-
|
56 |
-
actuals = [
|
57 |
-
{'date': date.strftime('%Y-%m-%d'), 'price': close} \
|
58 |
-
for date, close in zip(df_date, df_close)
|
59 |
-
]
|
60 |
-
|
61 |
-
return actuals, predictions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
training.py
DELETED
@@ -1,244 +0,0 @@
|
|
1 |
-
import os
|
2 |
-
import json
|
3 |
-
import joblib
|
4 |
-
import argparse
|
5 |
-
import numpy as np
|
6 |
-
import pandas as pd
|
7 |
-
|
8 |
-
from sklearn.preprocessing import StandardScaler, MinMaxScaler
|
9 |
-
|
10 |
-
from tensorflow.keras.models import Sequential
|
11 |
-
from tensorflow.keras.layers import GRU, LSTM, Dense, Dropout
|
12 |
-
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
from warnings import filterwarnings
|
17 |
-
filterwarnings('ignore')
|
18 |
-
|
19 |
-
class DataProcessor:
|
20 |
-
def __init__(self, datasets_path):
|
21 |
-
self.datasets_path = datasets_path
|
22 |
-
self.datasets = self._get_datasets()
|
23 |
-
|
24 |
-
def _get_datasets(self):
|
25 |
-
return sorted([
|
26 |
-
item for item in os.listdir(self.datasets_path)
|
27 |
-
if os.path.isfile(os.path.join(self.datasets_path, item)) and item.endswith('.csv')
|
28 |
-
])
|
29 |
-
|
30 |
-
@staticmethod
|
31 |
-
def create_sequences(df, sequence_length):
|
32 |
-
labels, sequences = [], []
|
33 |
-
for i in range(len(df) - sequence_length):
|
34 |
-
seq = df.iloc[i:i + sequence_length].values
|
35 |
-
label = df.iloc[i + sequence_length].values[0]
|
36 |
-
sequences.append(seq)
|
37 |
-
labels.append(label)
|
38 |
-
return np.array(sequences), np.array(labels)
|
39 |
-
|
40 |
-
@staticmethod
|
41 |
-
def preprocess_data(dataframe):
|
42 |
-
for col in dataframe.columns:
|
43 |
-
if dataframe[col].isnull().any():
|
44 |
-
if dataframe[col].dtype == 'object':
|
45 |
-
dataframe[col].fillna(dataframe[col].mode()[0], inplace = True)
|
46 |
-
else:
|
47 |
-
dataframe[col].fillna(dataframe[col].mean(), inplace = True)
|
48 |
-
return dataframe
|
49 |
-
|
50 |
-
@staticmethod
|
51 |
-
def scale_data(dataframe, scaler_cls):
|
52 |
-
scaler = scaler_cls()
|
53 |
-
dataframe['Close'] = scaler.fit_transform(dataframe[['Close']])
|
54 |
-
return scaler, dataframe
|
55 |
-
|
56 |
-
|
57 |
-
class ModelBuilder:
|
58 |
-
"""
|
59 |
-
GRU (Gated Recurrent Units) Model
|
60 |
-
"""
|
61 |
-
@staticmethod
|
62 |
-
def gru_model(input_shape):
|
63 |
-
model = Sequential([
|
64 |
-
GRU(50, return_sequences = True, input_shape = input_shape),
|
65 |
-
Dropout(0.2),
|
66 |
-
|
67 |
-
GRU(50, return_sequences = True),
|
68 |
-
Dropout(0.2),
|
69 |
-
|
70 |
-
GRU(50, return_sequences = True),
|
71 |
-
Dropout(0.2),
|
72 |
-
|
73 |
-
GRU(50, return_sequences = False),
|
74 |
-
Dropout(0.2),
|
75 |
-
|
76 |
-
Dense(units = 1)
|
77 |
-
])
|
78 |
-
model.compile(optimizer = 'nadam', loss = 'mean_squared_error')
|
79 |
-
return model
|
80 |
-
|
81 |
-
|
82 |
-
"""
|
83 |
-
LSTM (Long Short-Term Memory) Model
|
84 |
-
"""
|
85 |
-
@staticmethod
|
86 |
-
def lstm_model(input_shape):
|
87 |
-
model = Sequential([
|
88 |
-
LSTM(50, return_sequences = True, input_shape = input_shape),
|
89 |
-
Dropout(0.2),
|
90 |
-
|
91 |
-
LSTM(50, return_sequences = True),
|
92 |
-
Dropout(0.2),
|
93 |
-
|
94 |
-
LSTM(50, return_sequences = True),
|
95 |
-
Dropout(0.2),
|
96 |
-
|
97 |
-
LSTM(50, return_sequences = False),
|
98 |
-
Dropout(0.2),
|
99 |
-
|
100 |
-
Dense(units = 1)
|
101 |
-
])
|
102 |
-
model.compile(optimizer = 'nadam', loss = 'mean_squared_error')
|
103 |
-
return model
|
104 |
-
|
105 |
-
|
106 |
-
"""
|
107 |
-
LSTM (Long Short-Term Memory) and
|
108 |
-
GRU (Gated Recurrent Units) Model
|
109 |
-
"""
|
110 |
-
@staticmethod
|
111 |
-
def lstm_gru_model(input_shape):
|
112 |
-
model = Sequential([
|
113 |
-
LSTM(50, return_sequences = True, input_shape = input_shape),
|
114 |
-
Dropout(0.2),
|
115 |
-
|
116 |
-
GRU(50, return_sequences = True),
|
117 |
-
Dropout(0.2),
|
118 |
-
|
119 |
-
LSTM(50, return_sequences = True),
|
120 |
-
Dropout(0.2),
|
121 |
-
|
122 |
-
GRU(50, return_sequences = False),
|
123 |
-
Dropout(0.2),
|
124 |
-
|
125 |
-
Dense(units = 1)
|
126 |
-
])
|
127 |
-
model.compile(optimizer = 'nadam', loss = 'mean_squared_error')
|
128 |
-
return model
|
129 |
-
|
130 |
-
|
131 |
-
class Trainer:
|
132 |
-
def __init__(self, model, model_file, sequence_length, epochs, batch_size):
|
133 |
-
self.model = model
|
134 |
-
self.model_file = model_file
|
135 |
-
self.sequence_length = sequence_length
|
136 |
-
self.epochs = epochs
|
137 |
-
self.batch_size = batch_size
|
138 |
-
|
139 |
-
def train(self, X_train, y_train, X_test, y_test):
|
140 |
-
early_stopping = EarlyStopping(monitor = 'val_loss', patience = 5, mode = 'min')
|
141 |
-
|
142 |
-
model_checkpoint = ModelCheckpoint(
|
143 |
-
filepath = self.model_file,
|
144 |
-
save_best_only = True,
|
145 |
-
monitor = 'val_loss',
|
146 |
-
mode = 'min'
|
147 |
-
)
|
148 |
-
|
149 |
-
history = self.model.fit(
|
150 |
-
X_train, y_train,
|
151 |
-
epochs = self.epochs,
|
152 |
-
batch_size = self.batch_size,
|
153 |
-
validation_data = (X_test, y_test),
|
154 |
-
callbacks = [early_stopping, model_checkpoint]
|
155 |
-
)
|
156 |
-
|
157 |
-
return history
|
158 |
-
|
159 |
-
|
160 |
-
class PostProcessor:
|
161 |
-
@staticmethod
|
162 |
-
def inverse_transform(scaler, data):
|
163 |
-
return scaler.inverse_transform(data)
|
164 |
-
|
165 |
-
@staticmethod
|
166 |
-
def save_json(filename, data):
|
167 |
-
with open(filename, 'w') as f:
|
168 |
-
json.dump(data, f)
|
169 |
-
|
170 |
-
def main(algorithm: str, sequence_length: int, epochs: int, batch_size: int):
|
171 |
-
datasets_path = './datasets'
|
172 |
-
models_path = './models'
|
173 |
-
posttrained = './posttrained'
|
174 |
-
pickle_file = './pickles'
|
175 |
-
|
176 |
-
data_processor = DataProcessor(datasets_path)
|
177 |
-
|
178 |
-
for dataset in data_processor.datasets:
|
179 |
-
print(f"[TRAINING] {dataset.replace('.csv', '')} ")
|
180 |
-
|
181 |
-
dataframe = pd.read_csv(os.path.join(datasets_path, dataset), index_col='Date')[['Close']]
|
182 |
-
model_file = os.path.join(models_path, f"{dataset.replace('.csv', '')}.keras")
|
183 |
-
|
184 |
-
# dataframe = data_processor.preprocess_data(dataframe)
|
185 |
-
dataframe.dropna(inplace = True)
|
186 |
-
standard_scaler, dataframe = data_processor.scale_data(dataframe, StandardScaler)
|
187 |
-
minmax_scaler, dataframe = data_processor.scale_data(dataframe, MinMaxScaler)
|
188 |
-
|
189 |
-
sequences, labels = data_processor.create_sequences(dataframe, sequence_length)
|
190 |
-
input_shape = (sequences.shape[1], sequences.shape[2])
|
191 |
-
|
192 |
-
if algorithm == "GRU":
|
193 |
-
model = ModelBuilder.gru_model(input_shape)
|
194 |
-
|
195 |
-
elif algorithm == "LSTM":
|
196 |
-
model = ModelBuilder.lstm_model(input_shape)
|
197 |
-
|
198 |
-
elif algorithm == "LSTM_GRU":
|
199 |
-
model = ModelBuilder.lstm_gru_model(input_shape)
|
200 |
-
|
201 |
-
else: model = ModelBuilder.lstm_model(input_shape)
|
202 |
-
|
203 |
-
train_size = int(len(sequences) * 0.8)
|
204 |
-
X_train, X_test = sequences[:train_size], sequences[train_size:]
|
205 |
-
y_train, y_test = labels[:train_size], labels[train_size:]
|
206 |
-
|
207 |
-
trainer = Trainer(model, model_file, sequence_length, epochs, batch_size)
|
208 |
-
trainer.train(X_train, y_train, X_test, y_test)
|
209 |
-
|
210 |
-
dataframe_json = {'Date': dataframe.index.tolist(), 'Close': dataframe['Close'].tolist()}
|
211 |
-
|
212 |
-
PostProcessor.save_json(
|
213 |
-
os.path.join(posttrained, f'{dataset.replace(".csv", "")}-posttrained.json'),
|
214 |
-
dataframe_json
|
215 |
-
)
|
216 |
-
|
217 |
-
joblib.dump(minmax_scaler, os.path.join(pickle_file, f'{dataset.replace(".csv", "")}_minmax_scaler.pickle'))
|
218 |
-
joblib.dump(standard_scaler, os.path.join(pickle_file, f'{dataset.replace(".csv", "")}_standard_scaler.pickle'))
|
219 |
-
|
220 |
-
model.load_weights(model_file)
|
221 |
-
model.save(model_file)
|
222 |
-
|
223 |
-
print("\n\n")
|
224 |
-
|
225 |
-
|
226 |
-
if __name__ == "__main__":
|
227 |
-
parser = argparse.ArgumentParser(description = "Tebakaja Model Trainer")
|
228 |
-
|
229 |
-
parser.add_argument('-a', '--algorithm', type = str, required = True,
|
230 |
-
help = 'select the algorithm to be trained (LSTM, GRU, LSTM_GRU)')
|
231 |
-
|
232 |
-
parser.add_argument('-e', '--epochs', type = int, required = True, help = 'epochs')
|
233 |
-
parser.add_argument('-b', '--batchs', type = int, required = True, help = 'batch length')
|
234 |
-
parser.add_argument('-s', '--sequences', type = int, required = True, help = 'sequences length')
|
235 |
-
|
236 |
-
args = parser.parse_args()
|
237 |
-
|
238 |
-
main(
|
239 |
-
epochs = args.epochs,
|
240 |
-
batch_size = args.batchs,
|
241 |
-
algorithm = args.algorithm,
|
242 |
-
sequence_length = args.sequences
|
243 |
-
)
|
244 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
training/build/lib.linux-x86_64-3.10/data_processor.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (426 kB). View file
|
|
training/build/lib.linux-x86_64-3.10/main.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (493 kB). View file
|
|
training/build/lib.linux-x86_64-3.10/model_builder.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (395 kB). View file
|
|
training/build/lib.linux-x86_64-3.10/post_processor.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (319 kB). View file
|
|
training/build/lib.linux-x86_64-3.10/trainer.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (296 kB). View file
|
|
training/build/temp.linux-x86_64-3.10/data_processor.o
ADDED
Binary file (765 kB). View file
|
|
training/build/temp.linux-x86_64-3.10/main.o
ADDED
Binary file (890 kB). View file
|
|
training/build/temp.linux-x86_64-3.10/model_builder.o
ADDED
Binary file (699 kB). View file
|
|
training/build/temp.linux-x86_64-3.10/post_processor.o
ADDED
Binary file (572 kB). View file
|
|
training/build/temp.linux-x86_64-3.10/trainer.o
ADDED
Binary file (523 kB). View file
|
|
training/data_processor.c
ADDED
The diff for this file is too large to render.
See raw diff
|
|
training/data_processor.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (426 kB). View file
|
|
training/data_processor.pyx
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import numpy as np
|
3 |
+
|
4 |
+
from warnings import filterwarnings
|
5 |
+
filterwarnings('ignore')
|
6 |
+
|
7 |
+
|
8 |
+
""" Get Datasets """
|
9 |
+
async def get_datasets(str datasets_path):
|
10 |
+
cdef list items = os.listdir(datasets_path)
|
11 |
+
cdef list csv_files = []
|
12 |
+
cdef str item
|
13 |
+
|
14 |
+
for item in items:
|
15 |
+
if os.path.isfile(os.path.join(datasets_path, item)) and item.endswith('.csv'):
|
16 |
+
csv_files.append(item)
|
17 |
+
|
18 |
+
return sorted(csv_files)
|
19 |
+
|
20 |
+
|
21 |
+
""" Create Sequences """
|
22 |
+
async def create_sequences(df, int sequence_length):
|
23 |
+
cdef list labels = []
|
24 |
+
cdef list sequences = []
|
25 |
+
cdef int i
|
26 |
+
|
27 |
+
for i in range(len(df) - sequence_length):
|
28 |
+
seq = df.iloc[i:i + sequence_length].values
|
29 |
+
label = df.iloc[i + sequence_length].values[0]
|
30 |
+
sequences.append(seq)
|
31 |
+
labels.append(label)
|
32 |
+
|
33 |
+
return np.array(sequences), np.array(labels)
|
34 |
+
|
35 |
+
|
36 |
+
""" Pre-Process Data """
|
37 |
+
async def preprocess_data(dataframe):
|
38 |
+
cdef str col
|
39 |
+
|
40 |
+
for col in dataframe.columns:
|
41 |
+
if dataframe[col].isnull().any():
|
42 |
+
if dataframe[col].dtype == 'object':
|
43 |
+
dataframe[col].fillna(dataframe[col].mode()[0], inplace=True)
|
44 |
+
else:
|
45 |
+
dataframe[col].fillna(dataframe[col].mean(), inplace=True)
|
46 |
+
|
47 |
+
return dataframe
|
48 |
+
|
49 |
+
|
50 |
+
""" Scale Data """
|
51 |
+
async def scale_data(dataframe, scaler_cls):
|
52 |
+
scaler = scaler_cls()
|
53 |
+
dataframe['Close'] = scaler.fit_transform(dataframe[['Close']])
|
54 |
+
return scaler, dataframe
|
55 |
+
|
training/main.c
ADDED
The diff for this file is too large to render.
See raw diff
|
|
training/main.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (493 kB). View file
|
|
training/main.pyx
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import joblib
|
3 |
+
import argparse
|
4 |
+
import pandas as pd
|
5 |
+
from sklearn.preprocessing import StandardScaler, MinMaxScaler
|
6 |
+
|
7 |
+
|
8 |
+
from training.trainer import train
|
9 |
+
from training.post_processor import save_json, inverse_transform
|
10 |
+
from training.data_processor import (
|
11 |
+
scale_data,
|
12 |
+
get_datasets,
|
13 |
+
preprocess_data,
|
14 |
+
create_sequences
|
15 |
+
)
|
16 |
+
|
17 |
+
from training.model_builder import (
|
18 |
+
gru_model,
|
19 |
+
lstm_model,
|
20 |
+
lstm_gru_model
|
21 |
+
)
|
22 |
+
|
23 |
+
|
24 |
+
from warnings import filterwarnings
|
25 |
+
filterwarnings('ignore')
|
26 |
+
|
27 |
+
async def main(algorithm: str, sequence_length: int, epochs: int, batch_size: int):
|
28 |
+
datasets_path = './datasets'
|
29 |
+
models_path = './models'
|
30 |
+
posttrained = './posttrained'
|
31 |
+
pickle_file = './pickles'
|
32 |
+
|
33 |
+
|
34 |
+
for dataset in await get_datasets(datasets_path):
|
35 |
+
print(f"[TRAINING] {dataset.replace('.csv', '')} ")
|
36 |
+
|
37 |
+
dataframe = pd.read_csv(os.path.join(datasets_path, dataset), index_col='Date')[['Close']]
|
38 |
+
model_file = os.path.join(models_path, f"{dataset.replace('.csv', '')}.keras")
|
39 |
+
|
40 |
+
# dataframe = preprocess_data(dataframe)
|
41 |
+
dataframe.dropna(inplace = True)
|
42 |
+
standard_scaler, dataframe = await scale_data(dataframe, StandardScaler)
|
43 |
+
minmax_scaler, dataframe = await scale_data(dataframe, MinMaxScaler)
|
44 |
+
|
45 |
+
sequences, labels = await create_sequences(dataframe, sequence_length)
|
46 |
+
input_shape = (sequences.shape[1], sequences.shape[2])
|
47 |
+
|
48 |
+
if algorithm == "GRU":
|
49 |
+
model = await gru_model(input_shape)
|
50 |
+
|
51 |
+
elif algorithm == "LSTM":
|
52 |
+
model = await lstm_model(input_shape)
|
53 |
+
|
54 |
+
elif algorithm == "LSTM_GRU":
|
55 |
+
model = await lstm_gru_model(input_shape)
|
56 |
+
|
57 |
+
else: model = await lstm_model(input_shape)
|
58 |
+
|
59 |
+
train_size = int(len(sequences) * 0.8)
|
60 |
+
X_train, X_test = sequences[:train_size], sequences[train_size:]
|
61 |
+
y_train, y_test = labels[:train_size], labels[train_size:]
|
62 |
+
|
63 |
+
await train({
|
64 |
+
'model': model,
|
65 |
+
'model_file': model_file,
|
66 |
+
'sequence_length': sequence_length,
|
67 |
+
'epochs': epochs,
|
68 |
+
'batch_size': batch_size
|
69 |
+
}, X_train, y_train, X_test, y_test)
|
70 |
+
|
71 |
+
dataframe_json = {'Date': dataframe.index.tolist(), 'Close': dataframe['Close'].tolist()}
|
72 |
+
|
73 |
+
await save_json(
|
74 |
+
os.path.join(posttrained, f'{dataset.replace(".csv", "")}-posttrained.json'),
|
75 |
+
dataframe_json
|
76 |
+
)
|
77 |
+
|
78 |
+
joblib.dump(minmax_scaler, os.path.join(pickle_file, f'{dataset.replace(".csv", "")}_minmax_scaler.pickle'))
|
79 |
+
joblib.dump(standard_scaler, os.path.join(pickle_file, f'{dataset.replace(".csv", "")}_standard_scaler.pickle'))
|
80 |
+
|
81 |
+
model.load_weights(model_file)
|
82 |
+
model.save(model_file)
|
83 |
+
|
84 |
+
print("\n\n")
|
85 |
+
|
training/model_builder.c
ADDED
The diff for this file is too large to render.
See raw diff
|
|
training/model_builder.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (395 kB). View file
|
|
training/model_builder.pyx
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from tensorflow.keras.models import Sequential
|
2 |
+
from tensorflow.keras.layers import GRU, LSTM, Dense, Dropout
|
3 |
+
|
4 |
+
from warnings import filterwarnings
|
5 |
+
filterwarnings('ignore')
|
6 |
+
|
7 |
+
|
8 |
+
""" GRU (Gated Recurrent Units) Model """
|
9 |
+
async def gru_model(input_shape):
|
10 |
+
cdef object model = Sequential([
|
11 |
+
GRU(50, return_sequences = True, input_shape = input_shape),
|
12 |
+
Dropout(0.2),
|
13 |
+
|
14 |
+
GRU(50, return_sequences = True),
|
15 |
+
Dropout(0.2),
|
16 |
+
|
17 |
+
GRU(50, return_sequences = True),
|
18 |
+
Dropout(0.2),
|
19 |
+
|
20 |
+
GRU(50, return_sequences = False),
|
21 |
+
Dropout(0.2),
|
22 |
+
|
23 |
+
Dense(units = 1)
|
24 |
+
])
|
25 |
+
|
26 |
+
model.compile(optimizer = 'nadam', loss = 'mean_squared_error')
|
27 |
+
return model
|
28 |
+
|
29 |
+
|
30 |
+
""" LSTM (Long Short-Term Memory) Model """
|
31 |
+
async def lstm_model(input_shape):
|
32 |
+
cdef object model = Sequential([
|
33 |
+
LSTM(50, return_sequences = True, input_shape = input_shape),
|
34 |
+
Dropout(0.2),
|
35 |
+
|
36 |
+
LSTM(50, return_sequences = True),
|
37 |
+
Dropout(0.2),
|
38 |
+
|
39 |
+
LSTM(50, return_sequences = True),
|
40 |
+
Dropout(0.2),
|
41 |
+
|
42 |
+
LSTM(50, return_sequences = False),
|
43 |
+
Dropout(0.2),
|
44 |
+
|
45 |
+
Dense(units = 1)
|
46 |
+
])
|
47 |
+
|
48 |
+
model.compile(optimizer = 'nadam', loss = 'mean_squared_error')
|
49 |
+
return model
|
50 |
+
|
51 |
+
|
52 |
+
"""
|
53 |
+
LSTM (Long Short-Term Memory) and
|
54 |
+
GRU (Gated Recurrent Units) Model
|
55 |
+
"""
|
56 |
+
async def lstm_gru_model(input_shape):
|
57 |
+
cdef object model = Sequential([
|
58 |
+
LSTM(50, return_sequences = True, input_shape = input_shape),
|
59 |
+
Dropout(0.2),
|
60 |
+
|
61 |
+
GRU(50, return_sequences = True),
|
62 |
+
Dropout(0.2),
|
63 |
+
|
64 |
+
LSTM(50, return_sequences = True),
|
65 |
+
Dropout(0.2),
|
66 |
+
|
67 |
+
GRU(50, return_sequences = False),
|
68 |
+
Dropout(0.2),
|
69 |
+
|
70 |
+
Dense(units = 1)
|
71 |
+
])
|
72 |
+
|
73 |
+
model.compile(optimizer = 'nadam', loss = 'mean_squared_error')
|
74 |
+
return model
|
training/post_processor.c
ADDED
The diff for this file is too large to render.
See raw diff
|
|
training/post_processor.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (319 kB). View file
|
|
training/post_processor.pyx
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
from sklearn.preprocessing import MinMaxScaler
|
3 |
+
|
4 |
+
from warnings import filterwarnings
|
5 |
+
filterwarnings('ignore')
|
6 |
+
|
7 |
+
|
8 |
+
""" Inverse Transform """
|
9 |
+
async def inverse_transform(object scaler, data):
|
10 |
+
return scaler.inverse_transform(data)
|
11 |
+
|
12 |
+
|
13 |
+
""" save json """
|
14 |
+
async def save_json(str filename, data):
|
15 |
+
with open(filename, 'w') as f:
|
16 |
+
json.dump(data, f)
|
17 |
+
|
training/setup.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
from setuptools import setup
|
3 |
+
from Cython.Build import cythonize
|
4 |
+
|
5 |
+
setup(
|
6 |
+
ext_modules = cythonize([
|
7 |
+
# Model Builder
|
8 |
+
'model_builder.pyx',
|
9 |
+
|
10 |
+
# Data Processor
|
11 |
+
'data_processor.pyx',
|
12 |
+
|
13 |
+
# Post Processor
|
14 |
+
'post_processor.pyx',
|
15 |
+
|
16 |
+
# Trainer
|
17 |
+
'trainer.pyx',
|
18 |
+
|
19 |
+
# Main
|
20 |
+
'main.pyx'
|
21 |
+
]),
|
22 |
+
|
23 |
+
include_dirs = [ np.get_include() ]
|
24 |
+
)
|
training/trainer.c
ADDED
The diff for this file is too large to render.
See raw diff
|
|
training/trainer.cpython-310-x86_64-linux-gnu.so
ADDED
Binary file (296 kB). View file
|
|
training/trainer.pyx
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
|
2 |
+
|
3 |
+
from warnings import filterwarnings
|
4 |
+
filterwarnings('ignore')
|
5 |
+
|
6 |
+
|
7 |
+
""" Trainer """
|
8 |
+
async def train(dict configuration, X_train, y_train, X_test, y_test):
|
9 |
+
cdef object early_stopping = EarlyStopping(
|
10 |
+
monitor = 'val_loss',
|
11 |
+
patience = 5,
|
12 |
+
mode = 'min'
|
13 |
+
)
|
14 |
+
|
15 |
+
cdef object model_checkpoint = ModelCheckpoint(
|
16 |
+
filepath = configuration['model_file'],
|
17 |
+
save_best_only = True,
|
18 |
+
monitor = 'val_loss',
|
19 |
+
mode = 'min'
|
20 |
+
)
|
21 |
+
|
22 |
+
cdef object history = configuration['model'].fit(
|
23 |
+
X_train, y_train,
|
24 |
+
epochs = configuration['epochs'],
|
25 |
+
batch_size = configuration['batch_size'],
|
26 |
+
validation_data = (X_test, y_test),
|
27 |
+
callbacks = [ early_stopping, model_checkpoint ]
|
28 |
+
)
|
29 |
+
|
30 |
+
return history
|
31 |
+
|
trainingcli.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
import argparse
|
3 |
+
from training.main import main as training
|
4 |
+
|
5 |
+
|
6 |
+
def main() -> None:
|
7 |
+
parser = argparse.ArgumentParser(description = "Tebakaja Model Trainer")
|
8 |
+
|
9 |
+
parser.add_argument('-a', '--algorithm', type = str, required = True,
|
10 |
+
help = 'select the algorithm to be trained (LSTM, GRU, LSTM_GRU)')
|
11 |
+
|
12 |
+
parser.add_argument('-e', '--epochs', type = int, required = True, help = 'epochs')
|
13 |
+
parser.add_argument('-b', '--batchs', type = int, required = True, help = 'batch length')
|
14 |
+
parser.add_argument('-s', '--sequences', type = int, required = True, help = 'sequences length')
|
15 |
+
|
16 |
+
args = parser.parse_args()
|
17 |
+
event_loop = asyncio.get_event_loop()
|
18 |
+
|
19 |
+
event_loop.run_until_complete(
|
20 |
+
training(
|
21 |
+
epochs = args.epochs,
|
22 |
+
batch_size = args.batchs,
|
23 |
+
algorithm = args.algorithm,
|
24 |
+
sequence_length = args.sequences
|
25 |
+
)
|
26 |
+
)
|
27 |
+
|
28 |
+
|
29 |
+
if __name__ == "__main__": main()
|
30 |
+
|