-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9b85b57
commit b34c5fd
Showing
11 changed files
with
354 additions
and
289 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Oops, something went wrong.