Commit
·
0a7b47e
0
Parent(s):
Feat: Crafting LSTM, GRU, and LSTM_GRU model
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .github/workflows/gru_pipeline.yaml +187 -0
- .github/workflows/lstm_gru_pipeline.yaml +187 -0
- .github/workflows/lstm_pipeline.yaml +187 -0
- .gitignore +19 -0
- .vercelignore +7 -0
- Dockerfile +44 -0
- Makefile +2 -0
- README.md +16 -0
- app.py +28 -0
- converter.py +40 -0
- coret-coretan.ipynb +0 -0
- dev.requirements.txt +74 -0
- diagram/cryptocurrency_prediction.ai +0 -0
- diagram/cryptocurrency_prediction.jpg +0 -0
- diagram/icons/Yahoo!_Finance_logo_2021.png +0 -0
- diagram/icons/csv.png +0 -0
- diagram/icons/docker.png +0 -0
- diagram/icons/fastapi.png +0 -0
- diagram/icons/file.png +0 -0
- diagram/icons/github actions.png +0 -0
- diagram/icons/github.png +0 -0
- diagram/icons/golang.png +0 -0
- diagram/icons/json.png +0 -0
- diagram/icons/keras.png +0 -0
- diagram/icons/nestjs.png +0 -0
- diagram/icons/pickle.png +0 -0
- diagram/icons/spaces.png +0 -0
- diagram/icons/typescript.png +0 -0
- diagram/icons/vercel.png +0 -0
- go.mod +3 -0
- postman/Yahoo Finance.postman_collection.json +69 -0
- postman/response.json +0 -0
- postman/symbols.json +54 -0
- pyproject.toml +15 -0
- pyvenv.cfg +3 -0
- requirements.txt +13 -0
- restful/controllers.py +110 -0
- restful/cutils/build/lib.linux-x86_64-3.10/utilities.cpython-310-x86_64-linux-gnu.so +0 -0
- restful/cutils/build/temp.linux-x86_64-3.10/utilities.o +0 -0
- restful/cutils/setup.py +9 -0
- restful/cutils/utilities.c +0 -0
- restful/cutils/utilities.cpython-310-x86_64-linux-gnu.so +0 -0
- restful/cutils/utilities.pyx +56 -0
- restful/routes.py +25 -0
- restful/schemas.py +6 -0
- restful/services.py +19 -0
- restful/utilities.py +61 -0
- schedulers/gru_schedule.ctl +1 -0
- schedulers/lstm_gru_schedule.ctl +1 -0
- schedulers/lstm_schedule.ctl +1 -0
.github/workflows/gru_pipeline.yaml
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: GRU Pipeline
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches:
|
| 6 |
+
- main
|
| 7 |
+
tags:
|
| 8 |
+
- '*'
|
| 9 |
+
schedule:
|
| 10 |
+
- cron: "0 7 * * *"
|
| 11 |
+
# 14 - 7 = 7
|
| 12 |
+
|
| 13 |
+
jobs:
|
| 14 |
+
extraction_train_modeling:
|
| 15 |
+
name: Data Extraction, Training, and Modeling
|
| 16 |
+
runs-on: ubuntu-latest
|
| 17 |
+
|
| 18 |
+
steps:
|
| 19 |
+
- name: Set global directory
|
| 20 |
+
run: git config --global --add safe.directory /github/workspace
|
| 21 |
+
|
| 22 |
+
- uses: actions/checkout@v3
|
| 23 |
+
with:
|
| 24 |
+
lfs: true
|
| 25 |
+
persist-credentials: false
|
| 26 |
+
fetch-depth: 1
|
| 27 |
+
|
| 28 |
+
- name: Read pipeline schedule date
|
| 29 |
+
id: read_schedule
|
| 30 |
+
run: |
|
| 31 |
+
SCHEDULE_DATE=$(cat schedulers/lstm_gru_schedule.ctl)
|
| 32 |
+
echo "schedule_date=${SCHEDULE_DATE}" >> $GITHUB_ENV
|
| 33 |
+
|
| 34 |
+
- name: Get current date
|
| 35 |
+
id: get_date
|
| 36 |
+
run: echo "current_date=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
|
| 37 |
+
|
| 38 |
+
- name: Check if dates match
|
| 39 |
+
id: date_check
|
| 40 |
+
run: |
|
| 41 |
+
if [ "$schedule_date" = "$current_date" ]; then
|
| 42 |
+
echo "match=true" >> $GITHUB_ENV
|
| 43 |
+
else
|
| 44 |
+
echo "match=false" >> $GITHUB_ENV
|
| 45 |
+
fi
|
| 46 |
+
|
| 47 |
+
- name: Scraping Yahoo Finance
|
| 48 |
+
if: env.match != 'true'
|
| 49 |
+
run: |
|
| 50 |
+
mkdir datasets
|
| 51 |
+
wget https://github.com/belajarqywok/cryptocurrency_prediction/raw/main/postman/symbols.json \
|
| 52 |
+
-O postman/symbols.json
|
| 53 |
+
go run scraper.go
|
| 54 |
+
|
| 55 |
+
- name: Install Libraries
|
| 56 |
+
if: env.match != 'true'
|
| 57 |
+
run: pip install -r requirements.txt
|
| 58 |
+
|
| 59 |
+
- name: Modeling and Training
|
| 60 |
+
if: env.match != 'true'
|
| 61 |
+
run: |
|
| 62 |
+
mkdir models
|
| 63 |
+
mkdir pickles
|
| 64 |
+
mkdir posttrained
|
| 65 |
+
python training.py --algorithm=GRU
|
| 66 |
+
|
| 67 |
+
- name: Set Pipeline Schedule
|
| 68 |
+
if: env.match != 'true'
|
| 69 |
+
run: echo "$(date +'%Y-%m-%d')" > schedulers/lstm_gru_schedule.ctl
|
| 70 |
+
|
| 71 |
+
- name: Zip Posttrained, Models, and Pickles
|
| 72 |
+
if: env.match != 'true'
|
| 73 |
+
run: |
|
| 74 |
+
zip -r models.zip models
|
| 75 |
+
zip -r pickles.zip pickles
|
| 76 |
+
zip -r datasets.zip datasets
|
| 77 |
+
zip -r posttrained.zip posttrained
|
| 78 |
+
|
| 79 |
+
- name: Store Datasets to Google Drive
|
| 80 |
+
if: env.match != 'true'
|
| 81 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 82 |
+
with:
|
| 83 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 84 |
+
filename: datasets.zip
|
| 85 |
+
folderId: ${{ secrets.GDRIVE_CRYPTO_ID }}
|
| 86 |
+
name: datasets.zip
|
| 87 |
+
overwrite: "true"
|
| 88 |
+
|
| 89 |
+
- name: Store Models to Google Drive
|
| 90 |
+
if: env.match != 'true'
|
| 91 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 92 |
+
with:
|
| 93 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 94 |
+
filename: models.zip
|
| 95 |
+
folderId: ${{ secrets.GDRIVE_GRU_ID }}
|
| 96 |
+
name: models.zip
|
| 97 |
+
overwrite: "true"
|
| 98 |
+
|
| 99 |
+
- name: Store Pickles to Google Drive
|
| 100 |
+
if: env.match != 'true'
|
| 101 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 102 |
+
with:
|
| 103 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 104 |
+
filename: pickles.zip
|
| 105 |
+
folderId: ${{ secrets.GDRIVE_GRU_ID }}
|
| 106 |
+
name: pickles.zip
|
| 107 |
+
overwrite: "true"
|
| 108 |
+
|
| 109 |
+
- name: Store Posttrained to Google Drive
|
| 110 |
+
if: env.match != 'true'
|
| 111 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 112 |
+
with:
|
| 113 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 114 |
+
filename: posttrained.zip
|
| 115 |
+
folderId: ${{ secrets.GDRIVE_GRU_ID }}
|
| 116 |
+
name: posttrained.zip
|
| 117 |
+
overwrite: "true"
|
| 118 |
+
|
| 119 |
+
- name: Remove Temporarary Files and Directories
|
| 120 |
+
if: env.match != 'true'
|
| 121 |
+
run: |
|
| 122 |
+
rm models.zip
|
| 123 |
+
rm pickles.zip
|
| 124 |
+
rm datasets.zip
|
| 125 |
+
rm posttrained.zip
|
| 126 |
+
|
| 127 |
+
rm -rf models
|
| 128 |
+
rm -rf pickles
|
| 129 |
+
rm -rf datasets
|
| 130 |
+
rm -rf posttrained
|
| 131 |
+
|
| 132 |
+
- name: Commit changes
|
| 133 |
+
if: env.match != 'true'
|
| 134 |
+
run: |
|
| 135 |
+
git config --local user.email "[email protected]"
|
| 136 |
+
git config --local user.name "belajarqywok"
|
| 137 |
+
git add -A
|
| 138 |
+
git commit -m "Data Extraction, Training, and Modeling"
|
| 139 |
+
|
| 140 |
+
- name: Push changes
|
| 141 |
+
if: env.match != 'true'
|
| 142 |
+
uses: ad-m/github-push-action@master
|
| 143 |
+
with:
|
| 144 |
+
github_token: ${{ secrets.GH_TOKEN }}
|
| 145 |
+
branch: main
|
| 146 |
+
|
| 147 |
+
# model_deployment:
|
| 148 |
+
# name: Model Deployment
|
| 149 |
+
# runs-on: ubuntu-latest
|
| 150 |
+
# needs: extraction_train_modeling
|
| 151 |
+
# environment: Production
|
| 152 |
+
|
| 153 |
+
# env:
|
| 154 |
+
# HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
| 155 |
+
# SPACE_NAME: cryptocurrency_prediction
|
| 156 |
+
# HF_USERNAME: qywok
|
| 157 |
+
|
| 158 |
+
# steps:
|
| 159 |
+
# - name: Set global directory
|
| 160 |
+
# run: git config --global --add safe.directory /github/workspace
|
| 161 |
+
|
| 162 |
+
# - uses: actions/checkout@v3
|
| 163 |
+
# with:
|
| 164 |
+
# persist-credentials: false
|
| 165 |
+
# fetch-depth: 1000
|
| 166 |
+
|
| 167 |
+
# - name: Check git status
|
| 168 |
+
# run: git status
|
| 169 |
+
|
| 170 |
+
# - name: Configure git
|
| 171 |
+
# run: |
|
| 172 |
+
# git config --local user.email "[email protected]"
|
| 173 |
+
# git config --local user.name "qywok"
|
| 174 |
+
|
| 175 |
+
# - name: Pull changes from remote
|
| 176 |
+
# run: |
|
| 177 |
+
# git pull https://$HF_USERNAME:[email protected]/spaces/$HF_USERNAME/$SPACE_NAME main || \
|
| 178 |
+
# (git merge --strategy-option theirs)
|
| 179 |
+
|
| 180 |
+
# - name: Add and commit changes
|
| 181 |
+
# run: |
|
| 182 |
+
# git add -A
|
| 183 |
+
# git diff-index --quiet HEAD || git commit -m "Model Deployment"
|
| 184 |
+
|
| 185 |
+
# - name: Push to Hugging Face
|
| 186 |
+
# run: |
|
| 187 |
+
# git push https://$HF_USERNAME:[email protected]/spaces/$HF_USERNAME/$SPACE_NAME main --force
|
.github/workflows/lstm_gru_pipeline.yaml
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: LSTM GRU Pipeline
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches:
|
| 6 |
+
- main
|
| 7 |
+
tags:
|
| 8 |
+
- '*'
|
| 9 |
+
schedule:
|
| 10 |
+
- cron: "0 9 * * *"
|
| 11 |
+
# 16 - 7 = 9
|
| 12 |
+
|
| 13 |
+
jobs:
|
| 14 |
+
extraction_train_modeling:
|
| 15 |
+
name: Data Extraction, Training, and Modeling
|
| 16 |
+
runs-on: ubuntu-latest
|
| 17 |
+
|
| 18 |
+
steps:
|
| 19 |
+
- name: Set global directory
|
| 20 |
+
run: git config --global --add safe.directory /github/workspace
|
| 21 |
+
|
| 22 |
+
- uses: actions/checkout@v3
|
| 23 |
+
with:
|
| 24 |
+
lfs: true
|
| 25 |
+
persist-credentials: false
|
| 26 |
+
fetch-depth: 1
|
| 27 |
+
|
| 28 |
+
- name: Read pipeline schedule date
|
| 29 |
+
id: read_schedule
|
| 30 |
+
run: |
|
| 31 |
+
SCHEDULE_DATE=$(cat schedulers/lstm_gru_schedule.ctl)
|
| 32 |
+
echo "schedule_date=${SCHEDULE_DATE}" >> $GITHUB_ENV
|
| 33 |
+
|
| 34 |
+
- name: Get current date
|
| 35 |
+
id: get_date
|
| 36 |
+
run: echo "current_date=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
|
| 37 |
+
|
| 38 |
+
- name: Check if dates match
|
| 39 |
+
id: date_check
|
| 40 |
+
run: |
|
| 41 |
+
if [ "$schedule_date" = "$current_date" ]; then
|
| 42 |
+
echo "match=true" >> $GITHUB_ENV
|
| 43 |
+
else
|
| 44 |
+
echo "match=false" >> $GITHUB_ENV
|
| 45 |
+
fi
|
| 46 |
+
|
| 47 |
+
- name: Scraping Yahoo Finance
|
| 48 |
+
if: env.match != 'true'
|
| 49 |
+
run: |
|
| 50 |
+
mkdir datasets
|
| 51 |
+
wget https://github.com/belajarqywok/cryptocurrency_prediction/raw/main/postman/symbols.json \
|
| 52 |
+
-O postman/symbols.json
|
| 53 |
+
go run scraper.go
|
| 54 |
+
|
| 55 |
+
- name: Install Libraries
|
| 56 |
+
if: env.match != 'true'
|
| 57 |
+
run: pip install -r requirements.txt
|
| 58 |
+
|
| 59 |
+
- name: Modeling and Training
|
| 60 |
+
if: env.match != 'true'
|
| 61 |
+
run: |
|
| 62 |
+
mkdir models
|
| 63 |
+
mkdir pickles
|
| 64 |
+
mkdir posttrained
|
| 65 |
+
python training.py --algorithm=LSTM_GRU
|
| 66 |
+
|
| 67 |
+
- name: Set Pipeline Schedule
|
| 68 |
+
if: env.match != 'true'
|
| 69 |
+
run: echo "$(date +'%Y-%m-%d')" > schedulers/lstm_gru_schedule.ctl
|
| 70 |
+
|
| 71 |
+
- name: Zip Posttrained, Models, and Pickles
|
| 72 |
+
if: env.match != 'true'
|
| 73 |
+
run: |
|
| 74 |
+
zip -r models.zip models
|
| 75 |
+
zip -r pickles.zip pickles
|
| 76 |
+
zip -r datasets.zip datasets
|
| 77 |
+
zip -r posttrained.zip posttrained
|
| 78 |
+
|
| 79 |
+
- name: Store Datasets to Google Drive
|
| 80 |
+
if: env.match != 'true'
|
| 81 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 82 |
+
with:
|
| 83 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 84 |
+
filename: datasets.zip
|
| 85 |
+
folderId: ${{ secrets.GDRIVE_CRYPTO_ID }}
|
| 86 |
+
name: datasets.zip
|
| 87 |
+
overwrite: "true"
|
| 88 |
+
|
| 89 |
+
- name: Store Models to Google Drive
|
| 90 |
+
if: env.match != 'true'
|
| 91 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 92 |
+
with:
|
| 93 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 94 |
+
filename: models.zip
|
| 95 |
+
folderId: ${{ secrets.GDRIVE_LSTM_GRU_ID }}
|
| 96 |
+
name: models.zip
|
| 97 |
+
overwrite: "true"
|
| 98 |
+
|
| 99 |
+
- name: Store Pickles to Google Drive
|
| 100 |
+
if: env.match != 'true'
|
| 101 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 102 |
+
with:
|
| 103 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 104 |
+
filename: pickles.zip
|
| 105 |
+
folderId: ${{ secrets.GDRIVE_LSTM_GRU_ID }}
|
| 106 |
+
name: pickles.zip
|
| 107 |
+
overwrite: "true"
|
| 108 |
+
|
| 109 |
+
- name: Store Posttrained to Google Drive
|
| 110 |
+
if: env.match != 'true'
|
| 111 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 112 |
+
with:
|
| 113 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 114 |
+
filename: posttrained.zip
|
| 115 |
+
folderId: ${{ secrets.GDRIVE_LSTM_GRU_ID }}
|
| 116 |
+
name: posttrained.zip
|
| 117 |
+
overwrite: "true"
|
| 118 |
+
|
| 119 |
+
- name: Remove Temporarary Files and Directories
|
| 120 |
+
if: env.match != 'true'
|
| 121 |
+
run: |
|
| 122 |
+
rm models.zip
|
| 123 |
+
rm pickles.zip
|
| 124 |
+
rm datasets.zip
|
| 125 |
+
rm posttrained.zip
|
| 126 |
+
|
| 127 |
+
rm -rf models
|
| 128 |
+
rm -rf pickles
|
| 129 |
+
rm -rf datasets
|
| 130 |
+
rm -rf posttrained
|
| 131 |
+
|
| 132 |
+
- name: Commit changes
|
| 133 |
+
if: env.match != 'true'
|
| 134 |
+
run: |
|
| 135 |
+
git config --local user.email "[email protected]"
|
| 136 |
+
git config --local user.name "belajarqywok"
|
| 137 |
+
git add -A
|
| 138 |
+
git commit -m "Data Extraction, Training, and Modeling"
|
| 139 |
+
|
| 140 |
+
- name: Push changes
|
| 141 |
+
if: env.match != 'true'
|
| 142 |
+
uses: ad-m/github-push-action@master
|
| 143 |
+
with:
|
| 144 |
+
github_token: ${{ secrets.GH_TOKEN }}
|
| 145 |
+
branch: main
|
| 146 |
+
|
| 147 |
+
# model_deployment:
|
| 148 |
+
# name: Model Deployment
|
| 149 |
+
# runs-on: ubuntu-latest
|
| 150 |
+
# needs: extraction_train_modeling
|
| 151 |
+
# environment: Production
|
| 152 |
+
|
| 153 |
+
# env:
|
| 154 |
+
# HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
| 155 |
+
# SPACE_NAME: cryptocurrency_prediction
|
| 156 |
+
# HF_USERNAME: qywok
|
| 157 |
+
|
| 158 |
+
# steps:
|
| 159 |
+
# - name: Set global directory
|
| 160 |
+
# run: git config --global --add safe.directory /github/workspace
|
| 161 |
+
|
| 162 |
+
# - uses: actions/checkout@v3
|
| 163 |
+
# with:
|
| 164 |
+
# persist-credentials: false
|
| 165 |
+
# fetch-depth: 1000
|
| 166 |
+
|
| 167 |
+
# - name: Check git status
|
| 168 |
+
# run: git status
|
| 169 |
+
|
| 170 |
+
# - name: Configure git
|
| 171 |
+
# run: |
|
| 172 |
+
# git config --local user.email "[email protected]"
|
| 173 |
+
# git config --local user.name "qywok"
|
| 174 |
+
|
| 175 |
+
# - name: Pull changes from remote
|
| 176 |
+
# run: |
|
| 177 |
+
# git pull https://$HF_USERNAME:[email protected]/spaces/$HF_USERNAME/$SPACE_NAME main || \
|
| 178 |
+
# (git merge --strategy-option theirs)
|
| 179 |
+
|
| 180 |
+
# - name: Add and commit changes
|
| 181 |
+
# run: |
|
| 182 |
+
# git add -A
|
| 183 |
+
# git diff-index --quiet HEAD || git commit -m "Model Deployment"
|
| 184 |
+
|
| 185 |
+
# - name: Push to Hugging Face
|
| 186 |
+
# run: |
|
| 187 |
+
# git push https://$HF_USERNAME:[email protected]/spaces/$HF_USERNAME/$SPACE_NAME main --force
|
.github/workflows/lstm_pipeline.yaml
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: LSTM Pipeline
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches:
|
| 6 |
+
- main
|
| 7 |
+
tags:
|
| 8 |
+
- '*'
|
| 9 |
+
schedule:
|
| 10 |
+
- cron: "0 11 * * *"
|
| 11 |
+
# 18 - 7 = 11
|
| 12 |
+
|
| 13 |
+
jobs:
|
| 14 |
+
extraction_train_modeling:
|
| 15 |
+
name: Data Extraction, Training, and Modeling
|
| 16 |
+
runs-on: ubuntu-latest
|
| 17 |
+
|
| 18 |
+
steps:
|
| 19 |
+
- name: Set global directory
|
| 20 |
+
run: git config --global --add safe.directory /github/workspace
|
| 21 |
+
|
| 22 |
+
- uses: actions/checkout@v3
|
| 23 |
+
with:
|
| 24 |
+
lfs: true
|
| 25 |
+
persist-credentials: false
|
| 26 |
+
fetch-depth: 1
|
| 27 |
+
|
| 28 |
+
- name: Read pipeline schedule date
|
| 29 |
+
id: read_schedule
|
| 30 |
+
run: |
|
| 31 |
+
SCHEDULE_DATE=$(cat schedulers/lstm_schedule.ctl)
|
| 32 |
+
echo "schedule_date=${SCHEDULE_DATE}" >> $GITHUB_ENV
|
| 33 |
+
|
| 34 |
+
- name: Get current date
|
| 35 |
+
id: get_date
|
| 36 |
+
run: echo "current_date=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
|
| 37 |
+
|
| 38 |
+
- name: Check if dates match
|
| 39 |
+
id: date_check
|
| 40 |
+
run: |
|
| 41 |
+
if [ "$schedule_date" = "$current_date" ]; then
|
| 42 |
+
echo "match=true" >> $GITHUB_ENV
|
| 43 |
+
else
|
| 44 |
+
echo "match=false" >> $GITHUB_ENV
|
| 45 |
+
fi
|
| 46 |
+
|
| 47 |
+
- name: Scraping Yahoo Finance
|
| 48 |
+
if: env.match != 'true'
|
| 49 |
+
run: |
|
| 50 |
+
mkdir datasets
|
| 51 |
+
wget https://github.com/belajarqywok/cryptocurrency_prediction/raw/main/postman/symbols.json \
|
| 52 |
+
-O postman/symbols.json
|
| 53 |
+
go run scraper.go
|
| 54 |
+
|
| 55 |
+
- name: Install Libraries
|
| 56 |
+
if: env.match != 'true'
|
| 57 |
+
run: pip install -r requirements.txt
|
| 58 |
+
|
| 59 |
+
- name: Modeling and Training
|
| 60 |
+
if: env.match != 'true'
|
| 61 |
+
run: |
|
| 62 |
+
mkdir models
|
| 63 |
+
mkdir pickles
|
| 64 |
+
mkdir posttrained
|
| 65 |
+
python training.py --algorithm=LSTM
|
| 66 |
+
|
| 67 |
+
- name: Set Pipeline Schedule
|
| 68 |
+
if: env.match != 'true'
|
| 69 |
+
run: echo "$(date +'%Y-%m-%d')" > schedulers/lstm_schedule.ctl
|
| 70 |
+
|
| 71 |
+
- name: Zip Posttrained, Models, and Pickles
|
| 72 |
+
if: env.match != 'true'
|
| 73 |
+
run: |
|
| 74 |
+
zip -r models.zip models
|
| 75 |
+
zip -r pickles.zip pickles
|
| 76 |
+
zip -r datasets.zip datasets
|
| 77 |
+
zip -r posttrained.zip posttrained
|
| 78 |
+
|
| 79 |
+
- name: Store Datasets to Google Drive
|
| 80 |
+
if: env.match != 'true'
|
| 81 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 82 |
+
with:
|
| 83 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 84 |
+
filename: datasets.zip
|
| 85 |
+
folderId: ${{ secrets.GDRIVE_CRYPTO_ID }}
|
| 86 |
+
name: datasets.zip
|
| 87 |
+
overwrite: "true"
|
| 88 |
+
|
| 89 |
+
- name: Store Models to Google Drive
|
| 90 |
+
if: env.match != 'true'
|
| 91 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 92 |
+
with:
|
| 93 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 94 |
+
filename: models.zip
|
| 95 |
+
folderId: ${{ secrets.GDRIVE_LSTM_ID }}
|
| 96 |
+
name: models.zip
|
| 97 |
+
overwrite: "true"
|
| 98 |
+
|
| 99 |
+
- name: Store Pickles to Google Drive
|
| 100 |
+
if: env.match != 'true'
|
| 101 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 102 |
+
with:
|
| 103 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 104 |
+
filename: pickles.zip
|
| 105 |
+
folderId: ${{ secrets.GDRIVE_LSTM_ID }}
|
| 106 |
+
name: pickles.zip
|
| 107 |
+
overwrite: "true"
|
| 108 |
+
|
| 109 |
+
- name: Store Posttrained to Google Drive
|
| 110 |
+
if: env.match != 'true'
|
| 111 |
+
uses: adityak74/google-drive-upload-git-action@main
|
| 112 |
+
with:
|
| 113 |
+
credentials: ${{ secrets.GDRIVE_CRED }}
|
| 114 |
+
filename: posttrained.zip
|
| 115 |
+
folderId: ${{ secrets.GDRIVE_LSTM_ID }}
|
| 116 |
+
name: posttrained.zip
|
| 117 |
+
overwrite: "true"
|
| 118 |
+
|
| 119 |
+
- name: Remove Temporarary Files and Directories
|
| 120 |
+
if: env.match != 'true'
|
| 121 |
+
run: |
|
| 122 |
+
rm models.zip
|
| 123 |
+
rm pickles.zip
|
| 124 |
+
rm datasets.zip
|
| 125 |
+
rm posttrained.zip
|
| 126 |
+
|
| 127 |
+
rm -rf models
|
| 128 |
+
rm -rf pickles
|
| 129 |
+
rm -rf datasets
|
| 130 |
+
rm -rf posttrained
|
| 131 |
+
|
| 132 |
+
- name: Commit changes
|
| 133 |
+
if: env.match != 'true'
|
| 134 |
+
run: |
|
| 135 |
+
git config --local user.email "[email protected]"
|
| 136 |
+
git config --local user.name "belajarqywok"
|
| 137 |
+
git add -A
|
| 138 |
+
git commit -m "Data Extraction, Training, and Modeling"
|
| 139 |
+
|
| 140 |
+
- name: Push changes
|
| 141 |
+
if: env.match != 'true'
|
| 142 |
+
uses: ad-m/github-push-action@master
|
| 143 |
+
with:
|
| 144 |
+
github_token: ${{ secrets.GH_TOKEN }}
|
| 145 |
+
branch: main
|
| 146 |
+
|
| 147 |
+
# model_deployment:
|
| 148 |
+
# name: Model Deployment
|
| 149 |
+
# runs-on: ubuntu-latest
|
| 150 |
+
# needs: extraction_train_modeling
|
| 151 |
+
# environment: Production
|
| 152 |
+
|
| 153 |
+
# env:
|
| 154 |
+
# HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
| 155 |
+
# SPACE_NAME: cryptocurrency_prediction
|
| 156 |
+
# HF_USERNAME: qywok
|
| 157 |
+
|
| 158 |
+
# steps:
|
| 159 |
+
# - name: Set global directory
|
| 160 |
+
# run: git config --global --add safe.directory /github/workspace
|
| 161 |
+
|
| 162 |
+
# - uses: actions/checkout@v3
|
| 163 |
+
# with:
|
| 164 |
+
# persist-credentials: false
|
| 165 |
+
# fetch-depth: 1000
|
| 166 |
+
|
| 167 |
+
# - name: Check git status
|
| 168 |
+
# run: git status
|
| 169 |
+
|
| 170 |
+
# - name: Configure git
|
| 171 |
+
# run: |
|
| 172 |
+
# git config --local user.email "[email protected]"
|
| 173 |
+
# git config --local user.name "qywok"
|
| 174 |
+
|
| 175 |
+
# - name: Pull changes from remote
|
| 176 |
+
# run: |
|
| 177 |
+
# git pull https://$HF_USERNAME:[email protected]/spaces/$HF_USERNAME/$SPACE_NAME main || \
|
| 178 |
+
# (git merge --strategy-option theirs)
|
| 179 |
+
|
| 180 |
+
# - name: Add and commit changes
|
| 181 |
+
# run: |
|
| 182 |
+
# git add -A
|
| 183 |
+
# git diff-index --quiet HEAD || git commit -m "Model Deployment"
|
| 184 |
+
|
| 185 |
+
# - name: Push to Hugging Face
|
| 186 |
+
# run: |
|
| 187 |
+
# git push https://$HF_USERNAME:[email protected]/spaces/$HF_USERNAME/$SPACE_NAME main --force
|
.gitignore
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Postman
|
| 2 |
+
/postman/dataset.url
|
| 3 |
+
|
| 4 |
+
# Environments
|
| 5 |
+
/bin
|
| 6 |
+
/Lib
|
| 7 |
+
/lib64
|
| 8 |
+
/Include
|
| 9 |
+
/Scripts
|
| 10 |
+
|
| 11 |
+
# Pycache
|
| 12 |
+
/__pycache__
|
| 13 |
+
/restful/__pycache__
|
| 14 |
+
|
| 15 |
+
# Temp
|
| 16 |
+
/models
|
| 17 |
+
/pickles
|
| 18 |
+
/datasets
|
| 19 |
+
/posttrained
|
.vercelignore
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/.github
|
| 2 |
+
|
| 3 |
+
/bin
|
| 4 |
+
/include
|
| 5 |
+
/lib
|
| 6 |
+
|
| 7 |
+
/postman
|
Dockerfile
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.9-bullseye
|
| 2 |
+
|
| 3 |
+
LABEL organization="R6Q - Infraprasta University"
|
| 4 |
+
LABEL team="Group 5"
|
| 5 |
+
|
| 6 |
+
RUN useradd -m -u 1000 user
|
| 7 |
+
|
| 8 |
+
WORKDIR /app
|
| 9 |
+
|
| 10 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
| 11 |
+
|
| 12 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 13 |
+
|
| 14 |
+
COPY --chown=user . /app
|
| 15 |
+
|
| 16 |
+
RUN apt-get update && \
|
| 17 |
+
apt-get install -y gcc python3-dev gnupg curl
|
| 18 |
+
|
| 19 |
+
RUN pip install cython
|
| 20 |
+
|
| 21 |
+
RUN cd /app/restful/cutils && \
|
| 22 |
+
python setup.py build_ext --inplace && \
|
| 23 |
+
chmod 777 * && cd ../..
|
| 24 |
+
|
| 25 |
+
RUN pip install gdown
|
| 26 |
+
|
| 27 |
+
RUN --mount=type=secret,id=MODELS_ID,mode=0444,required=true \
|
| 28 |
+
gdown https://drive.google.com/uc?id=$(cat /run/secrets/MODELS_ID) && \
|
| 29 |
+
unzip models.zip && rm models.zip
|
| 30 |
+
|
| 31 |
+
RUN --mount=type=secret,id=PICKLES_ID,mode=0444,required=true \
|
| 32 |
+
gdown https://drive.google.com/uc?id=$(cat /run/secrets/PICKLES_ID) && \
|
| 33 |
+
unzip pickles.zip && rm pickles.zip
|
| 34 |
+
|
| 35 |
+
RUN --mount=type=secret,id=DATASETS_ID,mode=0444,required=true \
|
| 36 |
+
gdown https://drive.google.com/uc?id=$(cat /run/secrets/DATASETS_ID) && \
|
| 37 |
+
unzip datasets.zip && rm datasets.zip
|
| 38 |
+
|
| 39 |
+
RUN --mount=type=secret,id=POSTTRAINED_ID,mode=0444,required=true \
|
| 40 |
+
gdown https://drive.google.com/uc?id=$(cat /run/secrets/POSTTRAINED_ID) && \
|
| 41 |
+
unzip posttrained.zip && rm posttrained.zip
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--workers", "10", "--port", "7860"]
|
Makefile
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
cutils:
|
| 2 |
+
cd restful/cutils && python setup.py build_ext --inplace && cd ../..
|
README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Cryptocurrency Prediction Service
|
| 3 |
+
emoji: 📉
|
| 4 |
+
colorFrom: purple
|
| 5 |
+
colorTo: pink
|
| 6 |
+
sdk: docker
|
| 7 |
+
python_version: "3.10"
|
| 8 |
+
pinned: false
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
<h1 align="center">Cryptocurrency Prediction Service</h1>
|
| 13 |
+
<hr />
|
| 14 |
+
<p align="center">
|
| 15 |
+
<img src="./diagram/cryptocurrency_prediction.jpg"/>
|
| 16 |
+
</p>
|
app.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI
|
| 2 |
+
from restful.routes import route
|
| 3 |
+
from fastapi.responses import RedirectResponse
|
| 4 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 5 |
+
|
| 6 |
+
app = FastAPI(
|
| 7 |
+
title = "Cryptocurency Prediction Service",
|
| 8 |
+
version = "1.0"
|
| 9 |
+
)
|
| 10 |
+
|
| 11 |
+
# CORS Middleware
|
| 12 |
+
app.add_middleware(
|
| 13 |
+
CORSMiddleware,
|
| 14 |
+
allow_origins = ["*"],
|
| 15 |
+
allow_methods = ["*"],
|
| 16 |
+
allow_headers = ["*"],
|
| 17 |
+
allow_credentials = True,
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
app.include_router(
|
| 21 |
+
router = route,
|
| 22 |
+
prefix = '/crypto',
|
| 23 |
+
tags = ['Crypto']
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
@app.get("/", tags = ['Main'])
|
| 27 |
+
def root():
|
| 28 |
+
return RedirectResponse(url="/docs")
|
converter.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
Data Mining Assignment - Group 5
|
| 6 |
+
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
class JSONProcessor:
|
| 10 |
+
def __init__(self, input_file: str, output_file: str) -> None:
|
| 11 |
+
self.input_file: str = input_file
|
| 12 |
+
self.output_file: str = output_file
|
| 13 |
+
self.data = None
|
| 14 |
+
|
| 15 |
+
def load_json(self) -> None:
|
| 16 |
+
with open(self.input_file, 'r') as file:
|
| 17 |
+
self.data = json.load(file)
|
| 18 |
+
|
| 19 |
+
def extract_symbols(self) -> list:
|
| 20 |
+
if self.data is None:
|
| 21 |
+
raise ValueError("data not loaded. call load_json() first.")
|
| 22 |
+
quotes = self.data['finance']['result'][0]['quotes']
|
| 23 |
+
return [quote['symbol'] for quote in quotes]
|
| 24 |
+
|
| 25 |
+
def save_json(self, data: list) -> None:
|
| 26 |
+
with open(self.output_file, 'w') as file:
|
| 27 |
+
json.dump({'symbols': data}, file, indent = 4)
|
| 28 |
+
print(f'saved: {self.output_file}')
|
| 29 |
+
|
| 30 |
+
def main():
|
| 31 |
+
input_file = './postman/response.json'
|
| 32 |
+
output_file = './postman/symbols.json'
|
| 33 |
+
|
| 34 |
+
processor = JSONProcessor(input_file, output_file)
|
| 35 |
+
processor.load_json()
|
| 36 |
+
symbols = processor.extract_symbols()
|
| 37 |
+
processor.save_json(symbols)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
if __name__ == "__main__": main()
|
coret-coretan.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dev.requirements.txt
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
absl-py==2.1.0
|
| 2 |
+
annotated-types==0.7.0
|
| 3 |
+
anyio==4.4.0
|
| 4 |
+
astunparse==1.6.3
|
| 5 |
+
certifi==2024.2.2
|
| 6 |
+
charset-normalizer==3.3.2
|
| 7 |
+
click==8.1.7
|
| 8 |
+
dnspython==2.6.1
|
| 9 |
+
email_validator==2.1.1
|
| 10 |
+
exceptiongroup==1.2.1
|
| 11 |
+
fastapi==0.111.0
|
| 12 |
+
fastapi-cli==0.0.4
|
| 13 |
+
flatbuffers==24.3.25
|
| 14 |
+
gast==0.5.4
|
| 15 |
+
google-pasta==0.2.0
|
| 16 |
+
grpcio==1.64.0
|
| 17 |
+
h11==0.14.0
|
| 18 |
+
h5py==3.11.0
|
| 19 |
+
httpcore==1.0.5
|
| 20 |
+
httptools==0.6.1
|
| 21 |
+
httpx==0.27.0
|
| 22 |
+
idna==3.7
|
| 23 |
+
importlib_metadata==7.1.0
|
| 24 |
+
Jinja2==3.1.4
|
| 25 |
+
joblib==1.4.2
|
| 26 |
+
keras==3.3.3
|
| 27 |
+
libclang==18.1.1
|
| 28 |
+
Markdown==3.6
|
| 29 |
+
markdown-it-py==3.0.0
|
| 30 |
+
MarkupSafe==2.1.5
|
| 31 |
+
mdurl==0.1.2
|
| 32 |
+
ml-dtypes==0.3.2
|
| 33 |
+
namex==0.0.8
|
| 34 |
+
numpy==1.26.4
|
| 35 |
+
opt-einsum==3.3.0
|
| 36 |
+
optree==0.11.0
|
| 37 |
+
orjson==3.10.3
|
| 38 |
+
packaging==24.0
|
| 39 |
+
pandas==2.2.2
|
| 40 |
+
protobuf==4.25.3
|
| 41 |
+
pydantic==2.7.2
|
| 42 |
+
pydantic_core==2.18.3
|
| 43 |
+
Pygments==2.18.0
|
| 44 |
+
python-dateutil==2.9.0.post0
|
| 45 |
+
python-dotenv==1.0.1
|
| 46 |
+
python-multipart==0.0.9
|
| 47 |
+
pytz==2024.1
|
| 48 |
+
PyYAML==6.0.1
|
| 49 |
+
requests==2.32.3
|
| 50 |
+
rich==13.7.1
|
| 51 |
+
scikit-learn==1.5.0
|
| 52 |
+
scipy==1.13.1
|
| 53 |
+
shellingham==1.5.4
|
| 54 |
+
six==1.16.0
|
| 55 |
+
sniffio==1.3.1
|
| 56 |
+
starlette==0.37.2
|
| 57 |
+
tensorboard==2.16.2
|
| 58 |
+
tensorboard-data-server==0.7.2
|
| 59 |
+
tensorflow==2.16.1
|
| 60 |
+
tensorflow-io-gcs-filesystem==0.31.0
|
| 61 |
+
termcolor==2.4.0
|
| 62 |
+
threadpoolctl==3.5.0
|
| 63 |
+
typer==0.12.3
|
| 64 |
+
typing_extensions==4.12.1
|
| 65 |
+
tzdata==2024.1
|
| 66 |
+
ujson==5.10.0
|
| 67 |
+
urllib3==2.2.1
|
| 68 |
+
uvicorn==0.30.1
|
| 69 |
+
uvloop==0.19.0
|
| 70 |
+
watchfiles==0.22.0
|
| 71 |
+
websockets==12.0
|
| 72 |
+
Werkzeug==3.0.3
|
| 73 |
+
wrapt==1.16.0
|
| 74 |
+
zipp==3.19.1
|
diagram/cryptocurrency_prediction.ai
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
diagram/cryptocurrency_prediction.jpg
ADDED
|
diagram/icons/Yahoo!_Finance_logo_2021.png
ADDED
|
|
diagram/icons/csv.png
ADDED
|
|
diagram/icons/docker.png
ADDED
|
|
diagram/icons/fastapi.png
ADDED
|
|
diagram/icons/file.png
ADDED
|
|
diagram/icons/github actions.png
ADDED
|
|
diagram/icons/github.png
ADDED
|
|
diagram/icons/golang.png
ADDED
|
|
diagram/icons/json.png
ADDED
|
|
diagram/icons/keras.png
ADDED
|
|
diagram/icons/nestjs.png
ADDED
|
|
diagram/icons/pickle.png
ADDED
|
|
diagram/icons/spaces.png
ADDED
|
|
diagram/icons/typescript.png
ADDED
|
|
diagram/icons/vercel.png
ADDED
|
|
go.mod
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
module github.com/cryptocurrency_prediction
|
| 2 |
+
|
| 3 |
+
go 1.20
|
postman/Yahoo Finance.postman_collection.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"info": {
|
| 3 |
+
"_postman_id": "249fd388-44f6-45c2-9ad5-37da9c2af089",
|
| 4 |
+
"name": "Yahoo Finance",
|
| 5 |
+
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
| 6 |
+
},
|
| 7 |
+
"item": [
|
| 8 |
+
{
|
| 9 |
+
"name": "cryptocurrencies",
|
| 10 |
+
"request": {
|
| 11 |
+
"method": "POST",
|
| 12 |
+
"header": [
|
| 13 |
+
{
|
| 14 |
+
"key": "Cookie",
|
| 15 |
+
"value": "GUC=AQEBCAFmWUlmh0IaaAQw&s=AQAAAH-PIsT_&g=ZlgBjg; A1=d=AQABBBR-S2YCEF6h7KkHtT6kUMd5eQmdvDIFEgEBCAFJWWaHZlpOb2UB_eMBAAcIFH5LZgmdvDI&S=AQAAAge4BvAFwzWWdJFVm5Wyq9k; A3=d=AQABBBR-S2YCEF6h7KkHtT6kUMd5eQmdvDIFEgEBCAFJWWaHZlpOb2UB_eMBAAcIFH5LZgmdvDI&S=AQAAAge4BvAFwzWWdJFVm5Wyq9k; axids=gam=y-BdfSS7lE2uLV0LrGZqbRPm.8FUDjf.82~A&dv360=eS1EdjNSYkpGRTJ1R2RYQTAwYnNhcFJmQ0ZZN3BtTmNGan5B&ydsp=y-wmHAUIFE2uKC4PXfccNh1ff.Lz1oO0cj~A&tbla=y-gt8RDdJE2uKuvojQP3_mil11ZyoZelyw~A; tbla_id=f1c3e4ae-853f-47af-ba52-d13fe18de92e-tuctd4c1d85; PRF=t%3DBTC-USD%252BETH-USD%252BLTC-USD%252BLTC-INR%252BCU%253DF%26newChartbetateaser%3D0%252C1718255372183; A1S=d=AQABBBR-S2YCEF6h7KkHtT6kUMd5eQmdvDIFEgEBCAFJWWaHZlpOb2UB_eMBAAcIFH5LZgmdvDI&S=AQAAAge4BvAFwzWWdJFVm5Wyq9k; cmp=t=1717308407&j=0&u=1---; gpp=DBAA; gpp_sid=-1",
|
| 16 |
+
"type": "text"
|
| 17 |
+
}
|
| 18 |
+
],
|
| 19 |
+
"body": {
|
| 20 |
+
"mode": "raw",
|
| 21 |
+
"raw": "{\"offset\":0,\"size\":50,\"sortType\":\"DESC\",\"sortField\":\"intradaymarketcap\",\"quoteType\":\"CRYPTOCURRENCY\",\"query\":{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"currency\",\"USD\"]},{\"operator\":\"eq\",\"operands\":[\"exchange\",\"CCC\"]}]},\"userId\":\"\",\"userIdType\":\"guid\"}",
|
| 22 |
+
"options": {
|
| 23 |
+
"raw": {
|
| 24 |
+
"language": "json"
|
| 25 |
+
}
|
| 26 |
+
}
|
| 27 |
+
},
|
| 28 |
+
"url": {
|
| 29 |
+
"raw": "https://query2.finance.yahoo.com/v1/finance/screener?crumb=55ovV9srjcg&lang=en-US®ion=US&formatted=true&corsDomain=finance.yahoo.com",
|
| 30 |
+
"protocol": "https",
|
| 31 |
+
"host": [
|
| 32 |
+
"query2",
|
| 33 |
+
"finance",
|
| 34 |
+
"yahoo",
|
| 35 |
+
"com"
|
| 36 |
+
],
|
| 37 |
+
"path": [
|
| 38 |
+
"v1",
|
| 39 |
+
"finance",
|
| 40 |
+
"screener"
|
| 41 |
+
],
|
| 42 |
+
"query": [
|
| 43 |
+
{
|
| 44 |
+
"key": "crumb",
|
| 45 |
+
"value": "55ovV9srjcg"
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"key": "lang",
|
| 49 |
+
"value": "en-US"
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
"key": "region",
|
| 53 |
+
"value": "US"
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"key": "formatted",
|
| 57 |
+
"value": "true"
|
| 58 |
+
},
|
| 59 |
+
{
|
| 60 |
+
"key": "corsDomain",
|
| 61 |
+
"value": "finance.yahoo.com"
|
| 62 |
+
}
|
| 63 |
+
]
|
| 64 |
+
}
|
| 65 |
+
},
|
| 66 |
+
"response": []
|
| 67 |
+
}
|
| 68 |
+
]
|
| 69 |
+
}
|
postman/response.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
postman/symbols.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"symbols": [
|
| 3 |
+
"BTC-USD",
|
| 4 |
+
"ETH-USD",
|
| 5 |
+
"USDT-USD",
|
| 6 |
+
"BNB-USD",
|
| 7 |
+
"SOL-USD",
|
| 8 |
+
"STETH-USD",
|
| 9 |
+
"USDC-USD",
|
| 10 |
+
"XRP-USD",
|
| 11 |
+
"DOGE-USD",
|
| 12 |
+
"ADA-USD",
|
| 13 |
+
"TON11419-USD",
|
| 14 |
+
"SHIB-USD",
|
| 15 |
+
"AVAX-USD",
|
| 16 |
+
"WSTETH-USD",
|
| 17 |
+
"WETH-USD",
|
| 18 |
+
"LINK-USD",
|
| 19 |
+
"WBTC-USD",
|
| 20 |
+
"DOT-USD",
|
| 21 |
+
"TRX-USD",
|
| 22 |
+
"WTRX-USD",
|
| 23 |
+
"BCH-USD",
|
| 24 |
+
"NEAR-USD",
|
| 25 |
+
"MATIC-USD",
|
| 26 |
+
"LTC-USD",
|
| 27 |
+
"PEPE24478-USD",
|
| 28 |
+
"EETH-USD",
|
| 29 |
+
"UNI7083-USD",
|
| 30 |
+
"ICP-USD",
|
| 31 |
+
"LEO-USD",
|
| 32 |
+
"DAI-USD",
|
| 33 |
+
"WEETH-USD",
|
| 34 |
+
"ETC-USD",
|
| 35 |
+
"EZETH-USD",
|
| 36 |
+
"APT21794-USD",
|
| 37 |
+
"RNDR-USD",
|
| 38 |
+
"BTCB-USD",
|
| 39 |
+
"HBAR-USD",
|
| 40 |
+
"WHBAR-USD",
|
| 41 |
+
"WBETH-USD",
|
| 42 |
+
"IMX10603-USD",
|
| 43 |
+
"KAS-USD",
|
| 44 |
+
"ATOM-USD",
|
| 45 |
+
"ARB11841-USD",
|
| 46 |
+
"MNT27075-USD",
|
| 47 |
+
"FIL-USD",
|
| 48 |
+
"WIF-USD",
|
| 49 |
+
"XLM-USD",
|
| 50 |
+
"USDE29470-USD",
|
| 51 |
+
"CRO-USD",
|
| 52 |
+
"AR-USD"
|
| 53 |
+
]
|
| 54 |
+
}
|
pyproject.toml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[tool.poetry]
|
| 2 |
+
name = "cryptocurrency-prediction"
|
| 3 |
+
version = "0.1.0"
|
| 4 |
+
description = "Data Mining Assignment - Group 5"
|
| 5 |
+
authors = ["belajarqywok <[email protected]>"]
|
| 6 |
+
license = "MIT"
|
| 7 |
+
readme = "README.md"
|
| 8 |
+
|
| 9 |
+
[tool.poetry.dependencies]
|
| 10 |
+
python = "^3.9"
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
[build-system]
|
| 14 |
+
requires = ["poetry-core"]
|
| 15 |
+
build-backend = "poetry.core.masonry.api"
|
pyvenv.cfg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
home = /usr/bin
|
| 2 |
+
include-system-site-packages = false
|
| 3 |
+
version = 3.10.12
|
requirements.txt
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi==0.111.0
|
| 2 |
+
h5py==3.11.0
|
| 3 |
+
joblib==1.4.2
|
| 4 |
+
keras==3.3.3
|
| 5 |
+
numpy==1.26.4
|
| 6 |
+
pandas==2.2.2
|
| 7 |
+
protobuf==4.25.3
|
| 8 |
+
pydantic==2.7.2
|
| 9 |
+
pydantic_core==2.18.3
|
| 10 |
+
scikit-learn==1.5.0
|
| 11 |
+
scipy==1.13.1
|
| 12 |
+
tensorflow==2.16.1
|
| 13 |
+
uvicorn==0.30.1
|
restful/controllers.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from http import HTTPStatus
|
| 3 |
+
from fastapi.responses import JSONResponse
|
| 4 |
+
from restful.services import cryptocurrency_svc
|
| 5 |
+
from restful.schemas import CryptocurrencyPredictionSchema
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
# Cryptocurrency Controller
|
| 9 |
+
class cryptocurrency_controller:
|
| 10 |
+
# Cryptocurrency Service
|
| 11 |
+
__SERVICE = cryptocurrency_svc()
|
| 12 |
+
|
| 13 |
+
# Cryptocurrency List
|
| 14 |
+
async def crypto_list(self) -> JSONResponse:
|
| 15 |
+
try:
|
| 16 |
+
DATASETS_PATH = './datasets'
|
| 17 |
+
DATASETS = sorted(
|
| 18 |
+
[
|
| 19 |
+
item.replace(".csv", "") for item in os.listdir(DATASETS_PATH)
|
| 20 |
+
if os.path.isfile(os.path.join(DATASETS_PATH, item)) and item.endswith('.csv')
|
| 21 |
+
]
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
return JSONResponse(
|
| 25 |
+
content = {
|
| 26 |
+
'message': 'Success',
|
| 27 |
+
'status_code': HTTPStatus.OK,
|
| 28 |
+
'data': DATASETS
|
| 29 |
+
},
|
| 30 |
+
status_code = HTTPStatus.OK
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
except Exception as error_message:
|
| 34 |
+
print(error_message)
|
| 35 |
+
return JSONResponse(
|
| 36 |
+
content = {
|
| 37 |
+
'message': 'Internal Server Error',
|
| 38 |
+
'status_code': HTTPStatus.INTERNAL_SERVER_ERROR,
|
| 39 |
+
'data': None
|
| 40 |
+
},
|
| 41 |
+
status_code = HTTPStatus.INTERNAL_SERVER_ERROR
|
| 42 |
+
)
|
| 43 |
+
|
| 44 |
+
# Cryptocurrency Controller
|
| 45 |
+
async def prediction(self, payload: CryptocurrencyPredictionSchema) -> JSONResponse:
|
| 46 |
+
try:
|
| 47 |
+
DATASETS_PATH = './datasets'
|
| 48 |
+
DATASETS = sorted(
|
| 49 |
+
[
|
| 50 |
+
item.replace(".csv", "") for item in os.listdir(DATASETS_PATH)
|
| 51 |
+
if os.path.isfile(os.path.join(DATASETS_PATH, item)) and item.endswith('.csv')
|
| 52 |
+
]
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
# Validation
|
| 56 |
+
if (payload.days > 31) or (payload.days < 1):
|
| 57 |
+
return JSONResponse(
|
| 58 |
+
content = {
|
| 59 |
+
'message': 'prediction days cannot be more than a month and cannot be less than 1',
|
| 60 |
+
'status_code': HTTPStatus.BAD_REQUEST,
|
| 61 |
+
'data': None
|
| 62 |
+
},
|
| 63 |
+
status_code = HTTPStatus.BAD_REQUEST
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
if payload.currency not in DATASETS:
|
| 67 |
+
return JSONResponse(
|
| 68 |
+
content = {
|
| 69 |
+
'message': f'cryptocurrency {payload.currency} is not available.',
|
| 70 |
+
'status_code': HTTPStatus.BAD_REQUEST,
|
| 71 |
+
'data': None
|
| 72 |
+
},
|
| 73 |
+
status_code = HTTPStatus.BAD_REQUEST
|
| 74 |
+
)
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
prediction: dict = await self.__SERVICE.prediction(payload)
|
| 78 |
+
|
| 79 |
+
if not prediction :
|
| 80 |
+
return JSONResponse(
|
| 81 |
+
content = {
|
| 82 |
+
'message': 'prediction could not be generated, please try again.',
|
| 83 |
+
'status_code': HTTPStatus.BAD_REQUEST,
|
| 84 |
+
'data': None
|
| 85 |
+
},
|
| 86 |
+
status_code = HTTPStatus.BAD_REQUEST
|
| 87 |
+
)
|
| 88 |
+
|
| 89 |
+
return JSONResponse(
|
| 90 |
+
content = {
|
| 91 |
+
'message': 'prediction success',
|
| 92 |
+
'status_code': HTTPStatus.OK,
|
| 93 |
+
'data': {
|
| 94 |
+
'currency': payload.currency,
|
| 95 |
+
'predictions': prediction
|
| 96 |
+
}
|
| 97 |
+
},
|
| 98 |
+
status_code = HTTPStatus.OK
|
| 99 |
+
)
|
| 100 |
+
|
| 101 |
+
except Exception as error_message:
|
| 102 |
+
print(error_message)
|
| 103 |
+
return JSONResponse(
|
| 104 |
+
content = {
|
| 105 |
+
'message': 'internal server error',
|
| 106 |
+
'status_code': HTTPStatus.INTERNAL_SERVER_ERROR,
|
| 107 |
+
'data': None
|
| 108 |
+
},
|
| 109 |
+
status_code = HTTPStatus.INTERNAL_SERVER_ERROR
|
| 110 |
+
)
|
restful/cutils/build/lib.linux-x86_64-3.10/utilities.cpython-310-x86_64-linux-gnu.so
ADDED
|
Binary file (360 kB). View file
|
|
|
restful/cutils/build/temp.linux-x86_64-3.10/utilities.o
ADDED
|
Binary file (491 kB). View file
|
|
|
restful/cutils/setup.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from setuptools import setup
|
| 2 |
+
from Cython.Build import cythonize
|
| 3 |
+
import numpy
|
| 4 |
+
|
| 5 |
+
setup(
|
| 6 |
+
ext_modules=cythonize("utilities.pyx"),
|
| 7 |
+
include_dirs=[numpy.get_include()]
|
| 8 |
+
)
|
| 9 |
+
|
restful/cutils/utilities.c
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
restful/cutils/utilities.cpython-310-x86_64-linux-gnu.so
ADDED
|
Binary file (360 kB). View file
|
|
|
restful/cutils/utilities.pyx
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
from tensorflow.keras.models import load_model
|
| 6 |
+
import cython
|
| 7 |
+
|
| 8 |
+
cdef class Utilities:
|
| 9 |
+
async def cryptocurrency_prediction_utils(self,
|
| 10 |
+
int days, int sequence_length, str model_name) -> tuple:
|
| 11 |
+
cdef str model_path = os.path.join('./models', f'{model_name}.keras')
|
| 12 |
+
model = load_model(model_path)
|
| 13 |
+
|
| 14 |
+
cdef str dataframe_path = os.path.join('./posttrained', f'{model_name}-posttrained.json')
|
| 15 |
+
dataframe = read_json(dataframe_path)
|
| 16 |
+
dataframe.set_index('Date', inplace=True)
|
| 17 |
+
|
| 18 |
+
minmax_scaler = load(os.path.join('./pickles', f'{model_name}_minmax_scaler.pickle'))
|
| 19 |
+
standard_scaler = load(os.path.join('./pickles', f'{model_name}_standard_scaler.pickle'))
|
| 20 |
+
|
| 21 |
+
# Prediction
|
| 22 |
+
lst_seq = dataframe[-sequence_length:].values
|
| 23 |
+
lst_seq = expand_dims(lst_seq, axis=0)
|
| 24 |
+
|
| 25 |
+
cdef dict predicted_prices = {}
|
| 26 |
+
last_date = to_datetime(dataframe.index[-1])
|
| 27 |
+
|
| 28 |
+
for _ in range(days):
|
| 29 |
+
predicted_price = model.predict(lst_seq)
|
| 30 |
+
last_date = last_date + Timedelta(days=1)
|
| 31 |
+
|
| 32 |
+
predicted_prices[last_date] = minmax_scaler.inverse_transform(predicted_price)
|
| 33 |
+
predicted_prices[last_date] = standard_scaler.inverse_transform(predicted_prices[last_date])
|
| 34 |
+
|
| 35 |
+
lst_seq = append(lst_seq[:, 1:, :], [predicted_price], axis=1)
|
| 36 |
+
|
| 37 |
+
predictions = [
|
| 38 |
+
{'date': date.strftime('%Y-%m-%d'), 'price': float(price)} \
|
| 39 |
+
for date, price in predicted_prices.items()
|
| 40 |
+
]
|
| 41 |
+
|
| 42 |
+
# Actual
|
| 43 |
+
df_date = dataframe.index[-sequence_length:].values
|
| 44 |
+
df_date = [to_datetime(date) for date in df_date]
|
| 45 |
+
|
| 46 |
+
dataframe[['Close']] = minmax_scaler.inverse_transform(dataframe)
|
| 47 |
+
dataframe[['Close']] = standard_scaler.inverse_transform(dataframe)
|
| 48 |
+
df_close = dataframe.iloc[-sequence_length:]['Close'].values
|
| 49 |
+
|
| 50 |
+
actuals = [
|
| 51 |
+
{'date': date.strftime('%Y-%m-%d'), 'price': close} \
|
| 52 |
+
for date, close in zip(df_date, df_close)
|
| 53 |
+
]
|
| 54 |
+
|
| 55 |
+
return actuals, predictions
|
| 56 |
+
|
restful/routes.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, Body
|
| 2 |
+
from fastapi.responses import JSONResponse
|
| 3 |
+
from restful.controllers import cryptocurrency_controller
|
| 4 |
+
from restful.schemas import CryptocurrencyPredictionSchema
|
| 5 |
+
|
| 6 |
+
# Route
|
| 7 |
+
route = APIRouter()
|
| 8 |
+
|
| 9 |
+
# Controller
|
| 10 |
+
__CONTROLLER = cryptocurrency_controller()
|
| 11 |
+
|
| 12 |
+
# Cryptocurrency List
|
| 13 |
+
@route.get(path = '/lists')
|
| 14 |
+
async def cryptocurrency_list_route() -> JSONResponse:
|
| 15 |
+
# Cryptocurrency Controller
|
| 16 |
+
return await __CONTROLLER.crypto_list()
|
| 17 |
+
|
| 18 |
+
# Cryptocurrency Prediction
|
| 19 |
+
@route.post(path = '/prediction')
|
| 20 |
+
async def cryptocurrency_pred_route(
|
| 21 |
+
payload: CryptocurrencyPredictionSchema = Body(...)
|
| 22 |
+
) -> JSONResponse:
|
| 23 |
+
# Cryptocurrency Controller
|
| 24 |
+
return await __CONTROLLER.prediction(payload = payload)
|
| 25 |
+
|
restful/schemas.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pydantic import BaseModel
|
| 2 |
+
|
| 3 |
+
class CryptocurrencyPredictionSchema(BaseModel) :
|
| 4 |
+
days: int
|
| 5 |
+
currency: str
|
| 6 |
+
|
restful/services.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from restful.cutils.utilities import Utilities
|
| 2 |
+
from restful.schemas import CryptocurrencyPredictionSchema
|
| 3 |
+
|
| 4 |
+
class cryptocurrency_svc:
|
| 5 |
+
# Prediction Utilities
|
| 6 |
+
__PRED_UTILS = Utilities()
|
| 7 |
+
|
| 8 |
+
# Prediction Service
|
| 9 |
+
async def prediction(self, payload: CryptocurrencyPredictionSchema) -> dict:
|
| 10 |
+
days: int = payload.days
|
| 11 |
+
currency: str = payload.currency
|
| 12 |
+
|
| 13 |
+
actuals, predictions = await self.__PRED_UTILS.cryptocurrency_prediction_utils(
|
| 14 |
+
days = days,
|
| 15 |
+
model_name = currency,
|
| 16 |
+
sequence_length = 60
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
return {'actuals': actuals, 'predictions': predictions}
|
restful/utilities.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
schedulers/gru_schedule.ctl
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
2024-07-28
|
schedulers/lstm_gru_schedule.ctl
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
2024-07-28
|
schedulers/lstm_schedule.ctl
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
2024-07-28
|