├── birnn_model_optimized.pth ├── requirements.txt ├── upgrade-model.sh ├── birnn_model.py ├── app.py ├── Allora101Guide.md ├── alloraoneclickinstall.sh └── README.md /birnn_model_optimized.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xtnpxsgt/Allora-Comprehensive-Guide/HEAD/birnn_model_optimized.pth -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | flask[async] 2 | gunicorn[gthread] 3 | transformers[torch] 4 | pandas 5 | torch==2.0.1 6 | python-dotenv 7 | requests==2.31.0 8 | scikit-learn==1.3.1 9 | numpy==1.25.2 10 | joblib==1.3.2 11 | -------------------------------------------------------------------------------- /upgrade-model.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BOLD="\033[1m" 4 | UNDERLINE="\033[4m" 5 | LIGHT_BLUE="\033[1;34m" # Light Blue for primary messages 6 | BRIGHT_GREEN="\033[1;32m" # Bright Green for success messages 7 | MAGENTA="\033[1;35m" # Magenta for titles 8 | RESET="\033[0m" # Reset to default color 9 | 10 | echo -e "${LIGHT_BLUE}Upgrade Your Allora Model(Y/N):${RESET}" 11 | read -p "" installdep 12 | echo 13 | 14 | if [[ "$installdep" =~ ^[Yy]$ ]]; then 15 | 16 | echo -e "${LIGHT_BLUE}Clone & Replace old file :${RESET}" 17 | echo 18 | rm -rf app.py 19 | rm -rf requirements.txt 20 | wget -q https://raw.githubusercontent.com/0xtnpxsgt/Allora-Comprehensive-Guide/main/app.py -O /root/allora-huggingface-walkthrough/app.py 21 | wget -q https://raw.githubusercontent.com/0xtnpxsgt/Allora-Comprehensive-Guide/main/requirements.txt -O /root/allora-huggingface-walkthrough/requirements.txt 22 | wget -q https://github.com/0xtnpxsgt/Allora-Comprehensive-Guide/raw/main/birnn_model_optimized.pth -O /root/allora-huggingface-walkthrough/birnn_model_optimized.pth 23 | wait 24 | 25 | echo -e "${LIGHT_BLUE}Rebuild and run a model :${RESET}" 26 | 27 | cd /root/allora-huggingface-walkthrough/ 28 | echo 29 | docker compose up --build -d 30 | echo 31 | 32 | echo 33 | docker compose logs -f 34 | echo 35 | 36 | else 37 | echo -e "${BRIGHT_GREEN}Operation Canceled :${RESET}" 38 | 39 | fi 40 | 41 | echo 42 | echo -e "${MAGENTA}==============0xTnpxSGT | Allora===============${RESET}" 43 | -------------------------------------------------------------------------------- /birnn_model.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import pandas as pd 4 | import requests 5 | from sklearn.preprocessing import MinMaxScaler 6 | 7 | # Define the BiRNN model 8 | class BiRNNModel(nn.Module): 9 | def __init__(self, input_size, hidden_layer_size, output_size, num_layers, dropout): 10 | super(BiRNNModel, self).__init__() 11 | self.hidden_layer_size = hidden_layer_size 12 | self.num_layers = num_layers 13 | self.rnn = nn.RNN(input_size, hidden_layer_size, num_layers=num_layers, dropout=dropout, batch_first=True, bidirectional=True) 14 | self.linear = nn.Linear(hidden_layer_size * 2, output_size) # *2 because of bidirectional 15 | 16 | def forward(self, input_seq): 17 | h_0 = torch.zeros(self.num_layers * 2, input_seq.size(0), self.hidden_layer_size) # *2 for bidirection 18 | rnn_out, _ = self.rnn(input_seq, h_0) 19 | predictions = self.linear(rnn_out[:, -1]) 20 | return predictions 21 | 22 | # Function to fetch historical data from Binance 23 | def get_binance_data(symbol="ETHUSDT", interval="1m", limit=1000): 24 | url = f"https://api.binance.com/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}" 25 | response = requests.get(url) 26 | if response.status_code == 200: 27 | data = response.json() 28 | df = pd.DataFrame(data, columns=[ 29 | "open_time", "open", "high", "low", "close", "volume", 30 | "close_time", "quote_asset_volume", "number_of_trades", 31 | "taker_buy_base_asset_volume", "taker_buy_quote_asset_volume", "ignore" 32 | ]) 33 | df["close_time"] = pd.to_datetime(df["close_time"], unit='ms') 34 | df = df[["close_time", "close"]] 35 | df.columns = ["date", "price"] 36 | df["price"] = df["price"].astype(float) 37 | return df 38 | else: 39 | raise Exception(f"Failed to retrieve data: {response.text}") 40 | 41 | # Prepare the dataset 42 | def prepare_dataset(symbols, sequence_length=10): 43 | all_data = [] 44 | for symbol in symbols: 45 | df = get_binance_data(symbol) 46 | scaler = MinMaxScaler(feature_range=(-1, 1)) 47 | scaled_data = scaler.fit_transform(df['price'].values.reshape(-1, 1)) 48 | for i in range(sequence_length, len(scaled_data)): 49 | seq = scaled_data[i-sequence_length:i] 50 | label = scaled_data[i] 51 | all_data.append((seq, label)) 52 | return all_data, scaler 53 | 54 | # Define the training process 55 | def train_model(model, data, epochs=50, lr=0.001, sequence_length=10): 56 | criterion = nn.MSELoss() 57 | optimizer = torch.optim.Adam(model.parameters(), lr=lr) 58 | 59 | for epoch in range(epochs): 60 | epoch_loss = 0 61 | for seq, label in data: 62 | seq = torch.FloatTensor(seq).view(1, sequence_length, -1) 63 | label = torch.FloatTensor(label).view(1, -1) # Ensure label has the shape [batch_size, 1] 64 | 65 | optimizer.zero_grad() 66 | y_pred = model(seq) 67 | loss = criterion(y_pred, label) 68 | loss.backward() 69 | optimizer.step() 70 | 71 | epoch_loss += loss.item() 72 | 73 | print(f'Epoch {epoch+1}/{epochs}, Loss: {epoch_loss/len(data)}') 74 | 75 | torch.save(model.state_dict(), "birnn_model_optimized.pth") 76 | print("Model trained and saved as birnn_model_optimized.pth") 77 | 78 | if __name__ == "__main__": 79 | # Define the model 80 | model = BiRNNModel(input_size=1, hidden_layer_size=115, output_size=1, num_layers=2, dropout=0.3) 81 | 82 | # Symbols to train on 83 | symbols = ['BNBUSDT', 'BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'ARBUSDT'] 84 | 85 | # Prepare data 86 | data, scaler = prepare_dataset(symbols) 87 | 88 | # Train the model 89 | train_model(model, data) 90 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import pandas as pd 4 | from sklearn.preprocessing import MinMaxScaler 5 | import requests 6 | from flask import Flask, Response, json 7 | 8 | app = Flask(__name__) 9 | 10 | # Define the BiRNN model with the correct architecture 11 | class BiRNNModel(nn.Module): 12 | def __init__(self, input_size, hidden_layer_size, output_size, num_layers, dropout): 13 | super(BiRNNModel, self).__init__() 14 | self.hidden_layer_size = hidden_layer_size 15 | self.num_layers = num_layers 16 | self.rnn = nn.RNN(input_size, hidden_layer_size, num_layers=num_layers, dropout=dropout, batch_first=True, bidirectional=True) 17 | self.linear = nn.Linear(hidden_layer_size * 2, output_size) # *2 because of bidirectional 18 | 19 | def forward(self, input_seq): 20 | h_0 = torch.zeros(self.num_layers * 2, input_seq.size(0), self.hidden_layer_size) # *2 for bidirection 21 | rnn_out, _ = self.rnn(input_seq, h_0) 22 | predictions = self.linear(rnn_out[:, -1]) 23 | return predictions 24 | 25 | # Initialize the model with the same architecture as during training 26 | model = BiRNNModel(input_size=1, hidden_layer_size=115, output_size=1, num_layers=2, dropout=0.3) 27 | model.load_state_dict(torch.load("birnn_model_optimized.pth", weights_only=True)) 28 | model.eval() 29 | 30 | # Function to fetch historical data from Binance 31 | def get_binance_url(symbol="ETHUSDT", interval="1m", limit=1000): 32 | return f"https://api.binance.com/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}" 33 | 34 | @app.route("/inference/") 35 | def get_inference(token): 36 | if model is None: 37 | return Response(json.dumps({"error": "Model is not available"}), status=500, mimetype='application/json') 38 | 39 | symbol_map = { 40 | 'ETH': 'ETHUSDT', 41 | 'BTC': 'BTCUSDT', 42 | 'BNB': 'BNBUSDT', 43 | 'SOL': 'SOLUSDT', 44 | 'ARB': 'ARBUSDT' 45 | } 46 | 47 | token = token.upper() 48 | if token in symbol_map: 49 | symbol = symbol_map[token] 50 | else: 51 | return Response(json.dumps({"error": "Unsupported token"}), status=400, mimetype='application/json') 52 | 53 | url = get_binance_url(symbol=symbol) 54 | response = requests.get(url) 55 | if response.status_code == 200: 56 | data = response.json() 57 | df = pd.DataFrame(data, columns=[ 58 | "open_time", "open", "high", "low", "close", "volume", 59 | "close_time", "quote_asset_volume", "number_of_trades", 60 | "taker_buy_base_asset_volume", "taker_buy_quote_asset_volume", "ignore" 61 | ]) 62 | df["close_time"] = pd.to_datetime(df["close_time"], unit='ms') 63 | df = df[["close_time", "close"]] 64 | df.columns = ["date", "price"] 65 | df["price"] = df["price"].astype(float) 66 | 67 | # Adjust the number of rows based on the symbol 68 | if symbol in ['BTCUSDT', 'SOLUSDT']: 69 | df = df.tail(10) # Use last 10 minutes of data 70 | else: 71 | df = df.tail(20) # Use last 20 minutes of data 72 | 73 | # Prepare data for the BiRNN model 74 | scaler = MinMaxScaler(feature_range=(-1, 1)) 75 | scaled_data = scaler.fit_transform(df['price'].values.reshape(-1, 1)) 76 | 77 | seq = torch.FloatTensor(scaled_data).view(1, -1, 1) 78 | 79 | # Make prediction 80 | with torch.no_grad(): 81 | y_pred = model(seq) 82 | 83 | # Inverse transform the prediction to get the actual price 84 | predicted_price = scaler.inverse_transform(y_pred.numpy()) 85 | 86 | # Round the predicted price to 2 decimal places 87 | rounded_price = round(predicted_price.item(), 2) 88 | 89 | # Return the rounded price as a string 90 | return Response(str(rounded_price), status=200, mimetype='application/json') 91 | else: 92 | return Response(json.dumps({"error": "Failed to retrieve data from Binance API", "details": response.text}), 93 | status=response.status_code, 94 | mimetype='application/json') 95 | 96 | if __name__ == "__main__": 97 | app.run(host='0.0.0.0', port=8000) 98 | -------------------------------------------------------------------------------- /Allora101Guide.md: -------------------------------------------------------------------------------- 1 | # Allora Guide 2 | ![667ca11ef3c5440fdacd9c66_66464b1563777b5bd5e3ef02_allora-points-program-black](https://github.com/user-attachments/assets/fb524b13-49c1-4c8f-90d9-50a9be69130c) 3 | 4 | 5 | ### How to Install? 6 | ## OPTION 1: One-Click Installation Script 7 | Run Command: 8 | ```bash 9 | wget https://raw.githubusercontent.com/0xtnpxsgt/Allora-Comprehensive-Guide/main/alloraoneclickinstall.sh && chmod +x alloraoneclickinstall.sh && ./alloraoneclickinstall.sh 10 | ``` 11 | 12 | ------------------------------------------------------------------------------------ 13 | ## OPTION 2: Manual Installation Guide 14 | 15 | # Prerequisites 16 | Before you start, ensure you have docker compose installed. 17 | ```bash 18 | # Install Docker 19 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg 20 | 21 | echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 22 | 23 | sudo apt-get update 24 | sudo apt-get install docker-ce docker-ce-cli containerd.io 25 | docker version 26 | 27 | # Install Docker-Compose 28 | VER=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep tag_name | cut -d '"' -f 4) 29 | 30 | curl -L "https://github.com/docker/compose/releases/download/"$VER"/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 31 | 32 | chmod +x /usr/local/bin/docker-compose 33 | docker-compose --version 34 | 35 | # Docker Permission to user 36 | sudo groupadd docker 37 | sudo usermod -aG docker $USER 38 | ``` 39 | 40 | Clean Old Docker 41 | ``` 42 | docker compose down -v 43 | docker container prune 44 | cd $HOME && rm -rf allora-huggingface-walkthrough 45 | ``` 46 | 47 | ### Deployment - Read Carefully! 48 | ## Step 1-1: 49 | ```bash 50 | git clone https://github.com/allora-network/allora-huggingface-walkthrough 51 | cd allora-huggingface-walkthrough 52 | ``` 53 | 54 | ## Step 2: 55 | ```bash 56 | cp config.example.json config.json 57 | nano config.json 58 | ``` 59 | 60 | #### Edit addressKeyName & addressRestoreMnemonic / Copy & Paste Inside config.json 61 | ```bash 62 | { 63 | "wallet": { 64 | "addressKeyName": "test", 65 | "addressRestoreMnemonic": "", 66 | "alloraHomeDir": "/root/.allorad", 67 | "gas": "1000000", 68 | "gasAdjustment": 1.0, 69 | "nodeRpc": "https://rpc.ankr.com/allora_testnet/", 70 | "maxRetries": 1, 71 | "delay": 1, 72 | "submitTx": false 73 | }, 74 | "worker": [ 75 | { 76 | "topicId": 1, 77 | "inferenceEntrypointName": "api-worker-reputer", 78 | "loopSeconds": 4, 79 | "parameters": { 80 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 81 | "Token": "ETH" 82 | } 83 | }, 84 | { 85 | "topicId": 3, 86 | "inferenceEntrypointName": "api-worker-reputer", 87 | "loopSeconds": 6, 88 | "parameters": { 89 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 90 | "Token": "BTC" 91 | } 92 | }, 93 | { 94 | "topicId": 5, 95 | "inferenceEntrypointName": "api-worker-reputer", 96 | "loopSeconds": 8, 97 | "parameters": { 98 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 99 | "Token": "SOL" 100 | } 101 | }, 102 | { 103 | "topicId": 7, 104 | "inferenceEntrypointName": "api-worker-reputer", 105 | "loopSeconds": 2, 106 | "parameters": { 107 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 108 | "Token": "ETH" 109 | } 110 | }, 111 | { 112 | "topicId": 8, 113 | "inferenceEntrypointName": "api-worker-reputer", 114 | "loopSeconds": 3, 115 | "parameters": { 116 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 117 | "Token": "BNB" 118 | } 119 | }, 120 | { 121 | "topicId": 9, 122 | "inferenceEntrypointName": "api-worker-reputer", 123 | "loopSeconds": 5, 124 | "parameters": { 125 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 126 | "Token": "ARB" 127 | } 128 | } 129 | 130 | ] 131 | } 132 | ``` 133 | ## Step 3: Export 134 | ```bash 135 | chmod +x init.config 136 | ./init.config 137 | ``` 138 | 139 | ## Step 4: Run Script 140 | ```bash 141 | wget https://raw.githubusercontent.com/0xtnpxsgt/Allora-Comprehensive-Guide/main/upgrade-model.sh && chmod +x upgrade-model.sh && ./upgrade-model.sh 142 | ``` 143 | 144 | ------------------------------------------------------------- 145 | 146 | #### Check your wallet here: http://worker-tx.nodium.xyz/ 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /alloraoneclickinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Allora One-Click Installation Script 4 | 5 | # Ensure the script is run as root 6 | if [ "$(id -u)" != "0" ]; then 7 | echo "This script must be run as root. Please use 'sudo ./install_allora.sh'" 8 | exit 1 9 | fi 10 | 11 | # Update and install necessary dependencies 12 | apt-get update && apt-get upgrade -y 13 | apt-get install -y curl wget git nano jq 14 | 15 | # Install Docker 16 | echo "Installing Docker..." 17 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg 18 | echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 19 | sudo apt-get update 20 | sudo apt-get install -y docker-ce docker-ce-cli containerd.io 21 | docker version 22 | 23 | # Install Docker-Compose 24 | echo "Installing Docker Compose..." 25 | VER=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep tag_name | cut -d '"' -f 4) 26 | curl -L "https://github.com/docker/compose/releases/download/$VER/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 27 | chmod +x /usr/local/bin/docker-compose 28 | docker-compose --version 29 | 30 | # Add user to Docker group 31 | echo "Adding current user to the Docker group..." 32 | sudo groupadd docker 33 | sudo usermod -aG docker $USER 34 | 35 | # Clean up old Docker containers and files (if any) 36 | echo "Cleaning up old Docker containers and files..." 37 | docker compose down -v 38 | docker container prune -f 39 | cd $HOME && rm -rf allora-huggingface-walkthrough 40 | 41 | # Clone Allora repository 42 | echo "Cloning Allora repository..." 43 | git clone https://github.com/allora-network/allora-huggingface-walkthrough 44 | cd allora-huggingface-walkthrough 45 | 46 | # Copy example config and initialize it with default JSON structure 47 | cp config.example.json config.json 48 | 49 | # Insert the default JSON structure into config.json 50 | cat > config.json <", 55 | "alloraHomeDir": "/root/.allorad", 56 | "gas": "1000000", 57 | "gasAdjustment": 1.0, 58 | "nodeRpc": "https://rpc.ankr.com/allora_testnet/", 59 | "maxRetries": 1, 60 | "delay": 1, 61 | "submitTx": false 62 | }, 63 | "worker": [ 64 | { 65 | "topicId": 1, 66 | "inferenceEntrypointName": "api-worker-reputer", 67 | "loopSeconds": 4, 68 | "parameters": { 69 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 70 | "Token": "ETH" 71 | } 72 | }, 73 | { 74 | "topicId": 3, 75 | "inferenceEntrypointName": "api-worker-reputer", 76 | "loopSeconds": 6, 77 | "parameters": { 78 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 79 | "Token": "BTC" 80 | } 81 | }, 82 | { 83 | "topicId": 5, 84 | "inferenceEntrypointName": "api-worker-reputer", 85 | "loopSeconds": 8, 86 | "parameters": { 87 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 88 | "Token": "SOL" 89 | } 90 | }, 91 | { 92 | "topicId": 7, 93 | "inferenceEntrypointName": "api-worker-reputer", 94 | "loopSeconds": 2, 95 | "parameters": { 96 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 97 | "Token": "ETH" 98 | } 99 | }, 100 | { 101 | "topicId": 8, 102 | "inferenceEntrypointName": "api-worker-reputer", 103 | "loopSeconds": 3, 104 | "parameters": { 105 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 106 | "Token": "BNB" 107 | } 108 | }, 109 | { 110 | "topicId": 9, 111 | "inferenceEntrypointName": "api-worker-reputer", 112 | "loopSeconds": 5, 113 | "parameters": { 114 | "InferenceEndpoint": "http://inference:8000/inference/{Token}", 115 | "Token": "ARB" 116 | } 117 | } 118 | ] 119 | } 120 | EOL 121 | 122 | # Prompt user for addressKeyName and addressRestoreMnemonic 123 | read -p "Enter your addressKeyName: " addressKeyName 124 | read -p "Enter your addressRestoreMnemonic: " addressRestoreMnemonic 125 | 126 | # Update the config.json with user-provided values 127 | jq --arg keyName "$addressKeyName" --arg mnemonic "$addressRestoreMnemonic" \ 128 | '.wallet.addressKeyName = $keyName | .wallet.addressRestoreMnemonic = $mnemonic' config.json > temp.json && mv temp.json config.json 129 | 130 | # Export and run the initialization script 131 | chmod +x init.config 132 | ./init.config 133 | 134 | # Download and run the upgrade script 135 | echo "Downloading and running the upgrade script..." 136 | wget https://raw.githubusercontent.com/0xtnpxsgt/Allora-Comprehensive-Guide/main/upgrade-model.sh 137 | chmod +x upgrade-model.sh 138 | ./upgrade-model.sh 139 | 140 | echo "Installation complete! You can check your wallet here: http://worker-tx.nodium.xyz/" 141 | 142 | 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Allora: A Comprehensive Guide to Mastering Cryptocurrency Price Prediction with BiRNN 2 | "Mastering Cryptocurrency Price Prediction with BiRNN: A Comprehensive Guide from Model Creation to Real-Time Deployment" 3 | 4 | 5 | Introduction 6 | Predicting cryptocurrency prices is notoriously difficult due to the market's volatile and dynamic nature. However, advances in deep learning, particularly in Recurrent Neural Networks (RNNs) and their variants like Bidirectional RNNs (BiRNNs), provide us with the tools to model these complex patterns. This guide will walk you through the principles and practical steps for building, training, and deploying a BiRNN model for cryptocurrency price prediction. 7 | 8 | 9 | ## Section 1: Understanding the BiRNN Model 10 | What is a BiRNN? 11 | A Bidirectional Recurrent Neural Network (BiRNN) is an extension of a standard Recurrent Neural Network (RNN) that processes data in both forward and backward directions. This allows the model to capture dependencies from both past and future states, making it particularly useful for time-series predictions like cryptocurrency prices. 12 | 13 | 1. Understanding Time Series Data 14 | Time series data consists of sequential data points collected or recorded at specific time intervals. For cryptocurrencies, this typically includes prices at regular intervals (e.g., every minute, hour, or day). Understanding key characteristics like trend, seasonality, and noise is crucial when building a predictive model. 15 | 16 | 2. Introduction to Recurrent Neural Networks (RNNs) 17 | RNNs are a type of neural network designed specifically to handle sequential data. They are particularly useful for time series data because they can maintain a "memory" of previous inputs, allowing them to capture temporal dependencies. 18 | 19 | Key Features of RNNs: 20 | - Hidden State: Stores information from previous time steps. 21 | - Sequential Processing: Processes data in order, considering the context provided by previous steps. 22 | However, standard RNNs can struggle with long-term dependencies due to issues like vanishing gradients, making them less effective for long sequences. 23 | 24 | 25 | Benefits of BiRNNs: 26 | - Enhanced Context Understanding: Captures more comprehensive information by considering data in both directions. 27 | - Improved Accuracy: Often outperforms unidirectional RNNs in tasks requiring detailed context analysis 28 | 29 | 3. Building and Training a BiRNN Model 30 | 31 | Implementation Example: 32 | ```bash 33 | import torch 34 | import torch.nn as nn 35 | 36 | class BiRNNModel(nn.Module): 37 | def __init__(self, input_size, hidden_layer_size, output_size, num_layers, dropout): 38 | super(BiRNNModel, self).__init__() 39 | self.rnn = nn.RNN(input_size, hidden_layer_size, num_layers=num_layers, 40 | dropout=dropout, batch_first=True, bidirectional=True) 41 | self.linear = nn.Linear(hidden_layer_size * 2, output_size) 42 | 43 | def forward(self, input_seq): 44 | h0 = torch.zeros(self.num_layers * 2, input_seq.size(0), self.hidden_layer_size) 45 | rnn_out, _ = self.rnn(input_seq, h0) 46 | predictions = self.linear(rnn_out[:, -1]) 47 | return predictions 48 | ``` 49 | Data Collection and Preprocessing 50 | Data is collected using the Binance API, providing historical price data for various cryptocurrencies. The data is then preprocessed, typically involving: 51 | - Scaling: Normalizing data using techniques like Min-Max Scaling. 52 | - Feature Engineering: Creating features like moving averages or price changes that might help the model learn better. 53 | 54 | Fetching Data: 55 | ```bash 56 | def get_binance_data(symbols, interval="1m", limit=1000): 57 | # Function to fetch data from Binance 58 | ... 59 | 60 | ``` 61 | 62 | Training the Model 63 | We train the BiRNN model using historical data. The training process involves: 64 | - Loss Function: Using Mean Squared Error (MSE) to quantify the prediction error. 65 | - Optimizer: Utilizing Adam or similar optimizers to minimize the loss function. 66 | - Training Loop: Iterating over the data, updating the model's parameters based on the gradients computed from the loss. 67 | 68 | 69 | Training Example: 70 | ```bash 71 | model = BiRNNModel(input_size=1, hidden_layer_size=128, output_size=1, num_layers=2, dropout=0.3) 72 | criterion = nn.MSELoss() 73 | optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-5) 74 | 75 | for epoch in range(num_epochs): 76 | model.train() 77 | optimizer.zero_grad() 78 | output = model(train_seq) 79 | loss = criterion(output, train_labels) 80 | loss.backward() 81 | torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) # Gradient clipping 82 | optimizer.step() 83 | ``` 84 | 85 | 5. Fine-Tuning and Optimizing the Model 86 | To improve model performance, consider fine-tuning the following aspects: 87 | 88 | - Hidden Layer Size: Adjust to capture more complex patterns. 89 | - Number of Layers: More layers can model deeper patterns but may require careful tuning to avoid overfitting. 90 | - Learning Rate: Fine-tuning this can improve training stability and convergence. 91 | - Dropout Rate: Helps prevent overfitting by randomly dropping neurons during training. 92 | - Gradient Clipping: Prevents exploding gradients by capping the gradients during backpropagation. 93 | 94 | Example of Gradient Clipping: 95 | ```bash 96 | torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) 97 | ``` 98 | 99 | 100 | ## Section 2: Building the BiRNN Model 101 | 102 | 1. Setting Up the Environment 103 | First, ensure you have all the necessary libraries installed. You'll need torch, pandas, sklearn, and requests for this project. Install them using pip: 104 | ```bash 105 | pip install torch pandas scikit-learn requests flask 106 | ``` 107 | 108 | 2. Defining the BiRNN Model (model.py) 109 | Here's how you can define the BiRNN model: 110 | ```bash 111 | import torch 112 | import torch.nn as nn 113 | import pandas as pd 114 | import numpy as np 115 | from sklearn.preprocessing import MinMaxScaler 116 | import joblib 117 | 118 | class BiRNN(nn.Module): 119 | def __init__(self, input_size, hidden_size, output_size, num_layers, dropout): 120 | super(BiRNN, self).__init__() 121 | self.hidden_size = hidden_size 122 | self.num_layers = num_layers 123 | self.rnn = nn.RNN(input_size, hidden_size, num_layers, dropout=dropout, batch_first=True, bidirectional=True) 124 | self.fc = nn.Linear(hidden_size * 2, output_size) # Multiply by 2 for bidirectional 125 | 126 | def forward(self, x): 127 | h0 = torch.zeros(self.num_layers * 2, x.size(0), self.hidden_size) # Multiply by 2 for bidirectional 128 | out, _ = self.rnn(x, h0) 129 | out = self.fc(out[:, -1, :]) 130 | return out 131 | ``` 132 | 133 | ## Section 3: Training the BiRNN Model 134 | 135 | 1. Fetching Data from Binance API 136 | Use the following function to fetch historical data for the tokens: 137 | 138 | ``` 139 | import requests 140 | 141 | def get_binance_data(symbols=["ETHUSDT", "BTCUSDT", "BNBUSDT", "SOLUSDT", "ARBUSDT"], interval="1m", limit=1000): 142 | data_frames = {} 143 | for symbol in symbols: 144 | url = f"https://api.binance.com/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}" 145 | response = requests.get(url) 146 | data = response.json() 147 | df = pd.DataFrame(data, columns=[ 148 | "open_time", "open", "high", "low", "close", "volume", 149 | "close_time", "quote_asset_volume", "number_of_trades", 150 | "taker_buy_base_asset_volume", "taker_buy_quote_asset_volume", "ignore" 151 | ]) 152 | df["close"] = df["close"].astype(float) 153 | data_frames[symbol] = df[["close"]] 154 | return data_frames 155 | ``` 156 | 157 | 2. Preparing Data for Training 158 | Prepare the data by scaling it: 159 | ```bash 160 | data_frames = get_binance_data() 161 | scaler = MinMaxScaler(feature_range=(-1, 1)) 162 | scaled_data = {symbol: scaler.fit_transform(df.values) for symbol, df in data_frames.items()} 163 | 164 | # Save the scaler for later use 165 | joblib.dump(scaler, "scaler.save") 166 | ``` 167 | 168 | 3. Training the Model 169 | Train the BiRNN model using the following code: 170 | 171 | ```bash 172 | model = BiRNN(input_size=1, hidden_size=115, output_size=1, num_layers=2, dropout=0.3) 173 | criterion = nn.MSELoss() 174 | optimizer = torch.optim.Adam(model.parameters(), lr=0.001) 175 | num_epochs = 100 176 | 177 | for epoch in range(num_epochs): 178 | for symbol, data in scaled_data.items(): 179 | seq = torch.FloatTensor(data).view(1, -1, 1) 180 | labels = torch.FloatTensor(data[-1]).view(1, -1) 181 | 182 | optimizer.zero_grad() 183 | y_pred = model(seq) 184 | loss = criterion(y_pred, labels) 185 | loss.backward() 186 | torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) 187 | optimizer.step() 188 | 189 | # Save the model and scaler 190 | torch.save(model.state_dict(), "birnn_model.pth") 191 | ``` 192 | 193 | ## Section 4: Integrating the Model into the Flask Application 194 | 195 | 1. Loading the Model and Scaler in app.py 196 | Modify your app.py to load the trained BiRNN model: 197 | ```bash 198 | from flask import Flask, Response 199 | import torch 200 | import joblib 201 | import requests 202 | import pandas as pd 203 | 204 | app = Flask(__name__) 205 | 206 | class BiRNN(nn.Module): 207 | def __init__(self, input_size, hidden_size, output_size, num_layers, dropout): 208 | super(BiRNN, self).__init__() 209 | self.hidden_size = hidden_size 210 | self.num_layers = num_layers 211 | self.rnn = nn.RNN(input_size, hidden_size, num_layers, dropout=dropout, batch_first=True, bidirectional=True) 212 | self.fc = nn.Linear(hidden_size * 2, output_size) 213 | 214 | def forward(self, x): 215 | h0 = torch.zeros(self.num_layers * 2, x.size(0), self.hidden_size) 216 | out, _ = self.rnn(x, h0) 217 | out = self.fc(out[:, -1, :]) 218 | return out 219 | 220 | model = BiRNN(input_size=1, hidden_size=115, output_size=1, num_layers=2, dropout=0.3) 221 | model.load_state_dict(torch.load("birnn_model.pth")) 222 | model.eval() 223 | 224 | scaler = joblib.load("scaler.save") 225 | ``` 226 | 227 | 2. Making Predictions 228 | ```bash 229 | def get_binance_url(symbol="BTCUSDT", interval="1m", limit=1000): 230 | return f"https://api.binance.com/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}" 231 | 232 | @app.route("/inference/") 233 | def get_inference(token): 234 | token = token.upper() 235 | url = get_binance_url(symbol=token + "USDT") 236 | response = requests.get(url) 237 | 238 | if response.status_code == 200: 239 | data = response.json() 240 | df = pd.DataFrame(data, columns=[ 241 | "open_time", "open", "high", "low", "close", "volume", 242 | "close_time", "quote_asset_volume", "number_of_trades", 243 | "taker_buy_base_asset_volume", "taker_buy_quote_asset_volume", "ignore" 244 | ]) 245 | df["close"] = df["close"].astype(float) 246 | scaled_data = scaler.transform(df["close"].values.reshape(-1, 1)) 247 | seq = torch.FloatTensor(scaled_data).view(1, -1, 1) 248 | 249 | with torch.no_grad(): 250 | y_pred = model(seq) 251 | predicted_price = scaler.inverse_transform(y_pred.numpy()) 252 | return Response(str(round(predicted_price.item(), 2)), status=200, mimetype='application/json') 253 | else: 254 | return Response("Failed to retrieve data", status=500, mimetype='application/json') 255 | 256 | if __name__ == "__main__": 257 | app.run(host='0.0.0.0', port=8000) 258 | ``` 259 | 260 | 3. Build and Run Your Worker Node: 261 | ```bash 262 | docker compose up --build -d 263 | ``` 264 | 265 | Your Allora Worker Node is now ready to handle requests for real-time cryptocurrency price predictions. 266 | 267 | 268 | 269 | Key Steps: 270 | - Model Loading: The pre-trained model is loaded into memory when the Flask app starts. 271 | - Data Fetching: Historical data is retrieved for the requested cryptocurrency. 272 | - Inference: The BiRNN model processes the data and outputs a predicted price. 273 | - Response: The prediction is returned as a JSON response. 274 | 275 | 276 | Full Code Sample: 277 | - Full Code Sample Model.py: https://github.com/0xtnpxsgt/Allora-Comprehensive-Guide/blob/main/birnn_model.py 278 | - Full Code Sample App.py: https://github.com/0xtnpxsgt/Allora-Comprehensive-Guide/blob/main/app.py 279 | 280 | ## Conclusion 281 | This guide covers the entire process of building, training, and deploying a BiRNN model for cryptocurrency price prediction. By following the steps outlined here, you can develop a robust model capable of making real-time predictions, potentially providing valuable insights into market trends. 282 | Deep learning models like BiRNNs offer powerful tools for time series prediction, and with proper tuning and integration, they can be highly effective even in volatile markets like cryptocurrency. 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | --------------------------------------------------------------------------------