Skip to content

Commit

Permalink
Merge branch 'time-series-forcasting' of https://github.com/10-academ…
Browse files Browse the repository at this point in the history
…y-w-9/crypto-trading-backtesting into time-series-forcasting
  • Loading branch information
temesgen5335 committed Jun 26, 2024
2 parents 4c54df5 + a2eac42 commit 4396a9f
Show file tree
Hide file tree
Showing 479 changed files with 655 additions and 8,182 deletions.
2 changes: 2 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from flask_bcrypt import Bcrypt
import threading
from flask_cors import CORS
from flask_migrate import Migrate

db = SQLAlchemy()
jwt = JWTManager()
Expand All @@ -19,6 +20,7 @@ def create_app():
db.init_app(app)
jwt.init_app(app)
bcrypt.init_app(app)
migrate = Migrate(app, db)

CORS(app)

Expand Down
5 changes: 4 additions & 1 deletion app/models/backtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ class Backtest(db.Model):
__tablename__ = 'backtests'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))
symbol = db.Column(db.String(20))
start_date = db.Column(db.Date)
end_date = db.Column(db.Date)
status = db.Column(db.String(50))
inital_cash = db.Column(db.Integer)
fee = db.Column(db.Integer)
# status = db.Column(db.String(50))
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())

class Indicator(db.Model):
Expand Down
64 changes: 51 additions & 13 deletions app/routes/backtest.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,84 @@
import threading
from flask import Blueprint, request, jsonify, current_app
from app.models.backtest import Backtest, Parameter
from app.models.backtest import Backtest, Result
from app import db
from flask_jwt_extended import jwt_required
from app.services.backtest_service import run_backtest_by_id
from app.services.kafka_service import kafka_service
from flask_cors import CORS, cross_origin

bp = Blueprint('backtest', __name__)
CORS(bp)

@bp.route('/backtest', methods=['POST'])
@bp.route('/backtests', methods=['POST'])
@jwt_required()
@cross_origin(origin='*')
def run_backtest():
data = request.get_json()
name = data.get('name')
symbol = data.get('coin')
start_date = data.get('start_date')
end_date = data.get('end_date')
parameters = data.get('parameters')
inital_cash = data.get('inital_cash')
fee = data.get('fee')

# Check if backtest with same parameters exists
existing_backtest = Backtest.query.filter_by(name=name, start_date=start_date, end_date=end_date).first()
existing_backtest = Backtest.query.filter_by(name=name, symbol=symbol, start_date=start_date, end_date=end_date).first()
if existing_backtest:
return jsonify(
{"msg": "Backtest with same parameters already exists", "backtest_id": existing_backtest.id}), 200

# Create new backtest
new_backtest = Backtest(name=name, start_date=start_date, end_date=end_date, status="pending")
new_backtest = Backtest(name=name, symbol=symbol, start_date=start_date, end_date=end_date, inital_cash=inital_cash, fee = fee)
db.session.add(new_backtest)
db.session.commit()

# Add parameters
for param in parameters:
new_param = Parameter(backtest_id=new_backtest.id, indicator_id=param['indicator_id'], value=param['value'])
db.session.add(new_param)

db.session.commit()

# Publish backtest to Kafka for processing
kafka_service.produce('backtest_scenes', {
"backtest_id": new_backtest.id,
"parameters": parameters
"backtest_id": new_backtest.id
})

return jsonify({"msg": "Backtest created and published to Kafka", "backtest_id": new_backtest.id}), 201


@bp.route('/backtests', methods=['GET'])
@jwt_required()
@cross_origin(origin='*')
def get_backtests():
backtests = Backtest.query.all()
backtest_list = []
for backtest in backtests:
backtest_list.append({
'id': backtest.id,
'name': backtest.name,
'symbol': backtest.symbol,
'start_date': backtest.start_date.strftime('%Y-%m-%d'),
'end_date': backtest.end_date.strftime('%Y-%m-%d'),
'initial_cash': backtest.initial_cash,
'fee': backtest.fee,
'created_at': backtest.created_at.strftime('%Y-%m-%d %H:%M:%S')
})
return jsonify({'backtests': backtest_list}), 200

@bp.route('/backtests/<int:backtest_id>/results', methods=['GET'])
@jwt_required()
@cross_origin(origin='*')
def get_backtest_results(backtest_id):
results = Result.query.filter_by(backtest_id=backtest_id).all()
if not results:
return jsonify({'msg': 'No results found for this backtest'}), 404

result_list = []
for result in results:
result_list.append({
'id': result.id,
'total_return': float(result.total_return),
'number_of_trades': result.number_of_trades,
'winning_trades': result.winning_trades,
'losing_trades': result.losing_trades,
'max_drawdown': float(result.max_drawdown),
'sharpe_ratio': float(result.sharpe_ratio)
})

return jsonify({'results': result_list}), 200
2 changes: 1 addition & 1 deletion app/routes/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
def fetch_coins():
# Assuming you have a model named Coin
coins = Coin.query.all()
coin_list = [{'id': coin.id, 'name': coin.name, 'symbol': coin.symbol} for coin in coins]
coin_list = [{'id': coin.id, 'name': coin.name} for coin in coins]

return jsonify({'coins': coin_list}), 200

Expand Down
108 changes: 81 additions & 27 deletions app/services/backtest_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,93 @@
from app import db
from app.services.kafka_service import kafka_service
from app.services.mlflow_service import mlflow_service
from scripts.backtest_runner import RsiBollingerBandsStrategy, StochasticOscillatorStrategy, MacdStrategy
from scripts.backtest_runner import run_backtest, score_backtest

def run_backtest_by_id(backtest_id):
backtest = Backtest.query.get(backtest_id)
print('backtest', backtest.inital_cash)
if not backtest:
return


run_and_evaluate_backtest(backtest_id=backtest_id, symbol=backtest.symbol, initial_cash=backtest.inital_cash, fee=backtest.fee, start_date=backtest.start_date, end_date = backtest.end_date)
# for res in results:
# result = Result(**res)
# db.session.add(result)
# # Log metrics to MLflow
# metrics = {
# "total_return": res.total_return,
# "number_of_trades": res.number_of_trades,
# "winning_trades": res.winning_trades,
# "losing_trades": res.losing_trades,
# "max_drawdown": res.max_drawdown,
# "sharpe_ratio": res.sharpe_ratio
# }
# mlflow_service.log_metrics(run_name=f"Backtest_{backtest_id}", metrics=metrics)

# Publish result to Kafka
# kafka_service.produce('backtest_results', {
# "backtest_id": backtest_id,
# "metrics": metrics
# })
# db.session.commit()



def run_and_evaluate_backtest(backtest_id, symbol, initial_cash, fee, start_date, end_date):
strategies = [
RsiBollingerBandsStrategy,
MacdStrategy,
StochasticOscillatorStrategy
]

# Simulate backtest processing
result = Result(
backtest_id=backtest_id,
total_return=10.5,
number_of_trades=20,
winning_trades=15,
losing_trades=5,
max_drawdown=3.5,
sharpe_ratio=1.8
)
db.session.add(result)
db.session.commit()
results = []
for strategy in strategies:
result = run_backtest(strategy, symbol, initial_cash, fee, start_date, end_date)
result.backtest_id = backtest_id
result = Result(**result)
db.session.add(result)

# Log metrics to MLflow
metrics = {
"total_return": result.total_return,
"number_of_trades": result.number_of_trades,
"winning_trades": result.winning_trades,
"losing_trades": result.losing_trades,
"max_drawdown": result.max_drawdown,
"sharpe_ratio": result.sharpe_ratio
}
mlflow_service.log_metrics(run_name=f"Backtest_{backtest_id}", metrics=metrics)

# Log metrics to MLflow
metrics = {
"total_return": result.total_return,
"number_of_trades": result.number_of_trades,
"winning_trades": result.winning_trades,
"losing_trades": result.losing_trades,
"max_drawdown": result.max_drawdown,
"sharpe_ratio": result.sharpe_ratio
}
mlflow_service.log_metrics(run_name=f"Backtest_{backtest_id}", metrics=metrics)
# Publish result to Kafka
# kafka_service.produce('backtest_results', {
# "backtest_id": backtest_id,
# "metrics": metrics
# })
db.session.commit()

# Publish result to Kafka
kafka_service.produce('backtest_results', {
"backtest_id": backtest_id,
"metrics": metrics
})
results.append(result)

# Determine the min and max values for normalization
min_return = min(result['total_return'] for result in results)
max_return = max(result['total_return'] for result in results)
min_sharpe = min(result['sharpe_ratio'] for result in results)
max_sharpe = max(result['sharpe_ratio'] for result in results)
min_drawdown = min(result['max_drawdown'] for result in results)
max_drawdown = max(result['max_drawdown'] for result in results)

# Score each strategy
scores = [score_backtest(result) for result in results]

# Select the best strategy
best_strategy_index = scores.index(max(scores))
best_strategy = strategies[best_strategy_index]

print("Best Strategy:")
print(best_strategy.__name__)
print("Score:")
print(scores[best_strategy_index])
print("Metrics:")
print(results[best_strategy_index])
return results
Empty file removed app/templates/index.html
Empty file.
Empty file removed config/airflow.cfg
Empty file.
Empty file removed config/config.py
Empty file.
Empty file removed config/kafka-config.yaml
Empty file.
Empty file removed config/mlflow-config.yaml
Empty file.
25 changes: 0 additions & 25 deletions datas/binance/DOGEUSD_PERP-1h-2023-06-04.csv

This file was deleted.

Loading

0 comments on commit 4396a9f

Please sign in to comment.