Skip to content

Commit

Permalink
Merge pull request #6 from dev-abuke/frontend
Browse files Browse the repository at this point in the history
Frontend
  • Loading branch information
dev-abuke authored Jun 27, 2024
2 parents 571f235 + 66a3b60 commit 8edd97e
Show file tree
Hide file tree
Showing 77 changed files with 1,952 additions and 293 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ celerybeat.pid

# SageMath parsed files
*.sage.py

mlruns/
# Environments
.env
.venv
Expand Down
132 changes: 125 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
# Scalable Crypto Backtesting Infrastructure
# Scalable Stock and Crypto Backtesting Infrastructure

## Table of Contents

- [Installation](#installation)
- [Usage](#usage)
- [Project Structure](#project-structure)
- [Endpoints](#endpoints)
- [Kafka Integration](#kafka-integration)
- [LSTM Integration](#lstm-integration)
- [License](#license)

## Overview

Expand Down Expand Up @@ -56,7 +66,20 @@ pip install -r requirements.txt
```
## Project Structure
```bash
├── data/
├── backend/
│ ├── main.py
│ ├── models.py
│ ├── schemas.py
│ ├── database.py
│ ├── auth.py
│ ├── requirements.txt
│ ├── README.md
│ └── scripts
│ ├── backtesting
│ ├── init_data.py
│ ├── kafka_config.py
│ │ ├── main.py
│ └── init_db.py
├── scripts/
│ └── download_data.py
├── tests/
Expand All @@ -66,13 +89,108 @@ pip install -r requirements.txt
├── requirements.txt
└── README.md
```

### Set Up Kafka

If you do not have Kafka installed, you can run it using Docker:

docker run -d --name zookeeper -p 2181:2181 zookeeper:3.4.9
docker run -d --name kafka -p 9092:9092 --link zookeeper wurstmeister/kafka:latest

Alternatively, follow the [Kafka Quickstart](https://kafka.apache.org/quickstart) guide to set up Kafka.

### Configure Environment Variables

Create a `.env` file in the root directory and add the following configurations:

- KAFKA_BROKER_URL=localhost:9092
- SCENE_TOPIC=scene_parameters
- RESULT_TOPIC=backtest_results

### Initialize the Database

python -m scripts.init_db

## Backend Usage

### Run the FastAPI Application

uvicorn main:app --reload

### Sending Requests

Use a tool like Postman, Thunder Client, or Curl to interact with the API.

### Endpoints

### Health Check

**GET /health**

### Create Indicator

**POST /indicators/**

```sh
Body
{
"name": "Simple Moving Average",
"symbol": "SMA",
"description": "A simple moving average indicator"
}
```

### Read Indicators

**GET /indicators/**

### Create Stock

**POST /stocks/**

```sh
Body
{
"name": "Apple Inc.",
"symbol": "AAPL",
"description": "Apple Inc. stock"
}
```

### Read Stocks

**GET /stocks/**

### Create Scene

**POST /scenes/**

```sh
Body
{
"period": 20,
"indicator_id": 1,
"stock_id": 1,
"start_date": "2023-01-01",
"end_date": "2023-12-31"
}
```

### Read Scenes

**GET /scenes/**

### Perform Backtest

**POST /backtests/{scene_id}**

### Read Backtest Results

**GET /backtest_results/**

## Contributors
- Abubeker Shamil
- Addisu Alemu
- Michael George
- Sheila Murugi



## License
This project is licensed under the MIT License - see the LICENSE file for details.
Expand All @@ -85,4 +203,4 @@ This project is licensed under the MIT License - see the LICENSE file for detail
- Rehmet

**References:**
backtrader, Freqtrade, Vectorbt, Kafka, Airflow, MLflow, CML
backtrader, Freqtrade, Vectorbt, Kafka, Airflow, MLflow, CML
1 change: 1 addition & 0 deletions backend/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def get_current_user(db: Session = Depends(database.get_db), token: str = Depend

@router.post("/users/", response_model=schemas.User)
def create_user(user: schemas.UserCreate, db: Session = Depends(database.get_db)):
print("The user post is ::::::::: ", user)
hashed_password = get_password_hash(user.password)
db_user = models.User(email=user.email, hashed_password=hashed_password, full_name=user.full_name)
if db.query(models.User).filter(models.User.email == db_user.email).first():
Expand Down
32 changes: 18 additions & 14 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,24 +147,28 @@ def perform_backtest(scene_id: int, db: Session = Depends(get_db)):
db_scene = db.query(models.Scene).filter(models.Scene.id == scene_id).first()
if db_scene is None:
raise HTTPException(status_code=404, detail="Scene not found")

# Fetch data based on the scene's date range
df = fetch_data(db_scene.start_date, db_scene.end_date)

# Perform backtest
metrics = run_backtest({
'period': db_scene.period,
'indicator_name': db_scene.indicator.name
}, df)
config = {
'initial_cash': 500,
'start_date': db_scene.start_date.strftime('%Y-%m-%d'),
'end_date': db_scene.end_date.strftime('%Y-%m-%d'),
'ticker': db_scene.stock.symbol,
'indicator': db_scene.indicator.symbol
}

logger.info(f"Config: {config}")

metrics = run_backtest(config=config)

logger.info(f"Metrics: {metrics}")

# Save metrics to database
backtest_results = []
for metric in metrics:
db_backtest_result = models.BacktestResult(scene_id=scene_id, **metric)
db.add(db_backtest_result)
db.commit()
db.refresh(db_backtest_result)
backtest_results.append(db_backtest_result)
db_backtest_result = models.BacktestResult(scene_id=scene_id, **metrics)
db.add(db_backtest_result)
db.commit()
db.refresh(db_backtest_result)
backtest_results.append(db_backtest_result)

return backtest_results

Expand Down
1 change: 1 addition & 0 deletions backend/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class BacktestResult(Base):
initial_cash = Column(Float, nullable=False)
final_value = Column(Float, nullable=False)
percentage_return = Column(Float)
max_drawdown = Column(Float)
total_trades = Column(Integer)
winning_trades = Column(Integer)
losing_trades = Column(Integer)
Expand Down
3 changes: 2 additions & 1 deletion backend/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ class BacktestResultBase(BaseModel):
total_trades: int
winning_trades: int
losing_trades: int
sharpe_ratio: float
sharpe_ratio: Optional[float] = None
max_drawdown: Optional[float] = None

class BacktestResultCreate(BacktestResultBase):
pass
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import Navbar from './components/Navbar';
import BacktestForm from './components/BacktestForm';
import Signup from './components/Signup';
import Login from './components/Login';
import Profile from './components/Profile';

const PrivateRoute = ({ element: Element, ...rest }) => {
const token = localStorage.getItem('token');
return token ? <Element {...rest} /> : <Navigate to="/login" />;
};

function App() {
return (
Expand All @@ -15,7 +21,8 @@ function App() {
<Route path="/" element={<Navigate to="/login" />} />
<Route path="/signup" element={<Signup />} />
<Route path="/login" element={<Login />} />
<Route path="/backtest" element={<BacktestForm />} />
<Route path="/backtest" element={<PrivateRoute element={BacktestForm} />} />
<Route path="/profile" element={<PrivateRoute element={Profile} />} />
</Routes>
</div>
</div>
Expand Down
Loading

0 comments on commit 8edd97e

Please sign in to comment.