Skip to content

Commit

Permalink
updated
Browse files Browse the repository at this point in the history
  • Loading branch information
nafisalawalidris committed Aug 31, 2024
1 parent 9b85b57 commit b34c5fd
Show file tree
Hide file tree
Showing 11 changed files with 354 additions and 289 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CI

on: [push]

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: |
pytest
68 changes: 68 additions & 0 deletions app/crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from sqlalchemy.orm import Session
from .models import BitcoinPrice
import requests

def get_prices(db: Session, skip: int = 0, limit: int = 10):
return db.query(BitcoinPrice).offset(skip).limit(limit).all()

def get_prices_by_year(db: Session, year: int):
start_date = f'{year}-01-01'
end_date = f'{year}-12-31'
return db.query(BitcoinPrice).filter(BitcoinPrice.date.between(start_date, end_date)).all()

def get_prices_by_halving(db: Session, halving_number: int):
halving_periods = {
1: ('2012-11-28', '2016-07-09'),
2: ('2016-07-10', '2020-05-11'),
3: ('2020-05-12', '2024-04-30'),
4: ('2024-05-01', '2099-12-31') # Assumes the fourth period extends to a future date
}

start_date, end_date = halving_periods.get(halving_number, (None, None))

if start_date is None or end_date is None:
return [] # Consider raising an HTTPException or returning an appropriate error message

return db.query(BitcoinPrice).filter(
BitcoinPrice.date >= start_date,
BitcoinPrice.date <= end_date
).all()

def get_prices_across_halvings(db: Session):
return db.query(BitcoinPrice).all()

def get_bybit_prices():
try:
response = requests.get('https://api.bybit.com/v2/public/tickers')
response.raise_for_status() # Raises an HTTPError for bad responses
data = response.json()
return data.get('result', [])
except requests.RequestException as e:
# Log the error or handle it as needed
return {"error": str(e)}

def get_binance_prices():
try:
response = requests.get('https://api.binance.com/api/v3/ticker/price')
response.raise_for_status()
return response.json()
except requests.RequestException as e:
return {"error": str(e)}

def get_kraken_prices():
try:
response = requests.get('https://api.kraken.com/0/public/Ticker')
response.raise_for_status()
data = response.json()
return data.get('result', {})
except requests.RequestException as e:
return {"error": str(e)}

def get_yahoo_prices():
try:
response = requests.get('https://query1.finance.yahoo.com/v7/finance/quote?symbols=BTC-USD')
response.raise_for_status()
data = response.json()
return data.get('quoteResponse', {}).get('result', [])
except requests.RequestException as e:
return {"error": str(e)}
115 changes: 72 additions & 43 deletions app/database.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,87 @@
# Import necessary libraries from SQLAlchemy
from sqlalchemy import create_engine, Column, Date, Float, Integer
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from dotenv import load_dotenv
import os
import logging

# Load environment variables from .env file
load_dotenv()

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Get environment variables for database connection
POSTGRES_USER = os.getenv("POSTGRES_USER", "postgres")
POSTGRES_PASSWORD = os.getenv("POSTGRES_PASSWORD", "Feenah413")
POSTGRES_DB = os.getenv("POSTGRES_DB", "Bitcoin_Prices_Database")
POSTGRES_HOST = os.getenv("POSTGRES_HOST", "localhost")
POSTGRES_PORT = os.getenv("POSTGRES_PORT", "5432")

# Construct the database URL
SQLALCHEMY_DATABASE_URL = f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DB}"

# Create the SQLAlchemy engine
try:
engine = create_engine(SQLALCHEMY_DATABASE_URL)
logger.info("Database engine created successfully.")
except Exception as e:
logger.error(f"Failed to create database engine: {e}")
raise

# Base class for declarative models
Base = declarative_base()
import pandas as pd

# Define the database URL.
# Replace 'username', 'password', 'localhost', and 'dbname' with your PostgreSQL credentials.
DATABASE_URL = "postgresql://postgres:Feenah413@localhost/Bitcoin_Prices_Database"

# Create the SQLAlchemy engine.
# The engine is responsible for connecting to the database and executing SQL commands.
# We use 'create_engine' to initialize the connection to the PostgreSQL database.
engine = create_engine(DATABASE_URL, echo=True) # echo=True logs all the SQL commands

# Configure the session factory
# Create a SessionLocal class that will serve as a factory for creating new Session objects.
# Sessions are used to interact with the database and perform CRUD operations.
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# Dependency for database session
# Create a base class for our models.
# All model classes will inherit from this base class.
# The base class is used to create the database schema and manage the metadata.
Base = declarative_base()

# Dependency for getting a database session.
# This function will be used in FastAPI endpoints to get a session for interacting with the database.
def get_db():
# Create a new session.
db = SessionLocal()
try:
# Yield the session object to be used in the request.
yield db
finally:
# Close the session when done.
db.close()

# Function to test the database connection
def test_connection():
# Load the dataset from a CSV file
# Use raw string (r'path') or double backslashes for Windows paths
df = pd.read_csv(r"C:\Users\USER\Downloads\Bitcoin-Price-Analysis-API\data\BTC-USD Yahoo Finance - Max Yrs.csv", parse_dates=['Date'])

# Check for missing values
print(df.isnull().sum())

# Drop rows with missing values (if necessary)
df = df.dropna()

# Convert columns to appropriate data types
df['Date'] = pd.to_datetime(df['Date']) # Ensure 'Date' is in datetime format
df['Volume'] = df['Volume'].astype(int) # Convert 'Volume' to integer

class BitcoinPrice(Base):
__tablename__ = 'bitcoin_prices'

date = Column(Date, primary_key=True)
open = Column(Float)
high = Column(Float)
low = Column(Float)
close = Column(Float)
adj_close = Column(Float)
volume = Column(Integer)

# Create the table
Base.metadata.create_all(bind=engine)

def insert_data(df):
session = SessionLocal()
try:
with engine.connect() as connection:
logger.info("Connected to the database successfully.")
for _, row in df.iterrows():
price = BitcoinPrice(
date=row['Date'],
open=row['Open'],
high=row['High'],
low=row['Low'],
close=row['Close'],
adj_close=row['Adj Close'],
volume=row['Volume']
)
session.add(price)
session.commit()
except Exception as e:
logger.error(f"Failed to connect to the database: {e}")
raise
session.rollback()
print(f"Error: {e}")
finally:
session.close()

if __name__ == "__main__":
# Test the database connection
test_connection()
# Insert the data
insert_data(df)
Loading

0 comments on commit b34c5fd

Please sign in to comment.