from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates from fastapi.staticfiles import StaticFiles from pymongo import MongoClient from datetime import datetime import uvicorn from urllib.parse import quote_plus from dotenv import load_dotenv import os import yaml with open("coin.yaml", "r") as file: data = yaml.safe_load(file) interest_coins = data["interest"] load_dotenv() app = FastAPI() app.mount("/static", StaticFiles(directory="static"), name="static") data_points = [] # Setup templates directory templates = Jinja2Templates(directory="templates") MONGO_URI = f'mongodb://{quote_plus(os.getenv("DB_USER"))}:{quote_plus(os.getenv("DB_PWD"))}@{os.getenv("DB_HOST")}:{os.getenv("DB_PORT")}' client = MongoClient(MONGO_URI) db = client[os.getenv("DB_NAME")] # Replace with your database name # collection = db["XRP"] @app.get("/", response_class=HTMLResponse) async def read_data(request: Request): return templates.TemplateResponse( request=request, name="index.html", context={"coins": interest_coins} ) @app.get("/coin/{coin}") async def view_coin_graph(request: Request, coin: str): if coin in interest_coins: return templates.TemplateResponse( request=request, name="coin.html", context={"coin": coin} ) else: return {"coin": "not found"} @app.get("/coin/{coin}/candle1min") async def view_coin_candle_graph(request: Request, coin: str): if coin in interest_coins: return templates.TemplateResponse( request=request, name="candle_coin.html", context={"coin": coin} ) else: return {"coin": "not found"} @app.post("/update-data") async def update_data(data: dict): data_points.append(data) # Keep only last 300 points to ensure we have enough data to generate 100 candles if len(data_points) > 300: data_points.pop(0) return {"status": "success"} @app.get("/data/{coin}") async def get_data(coin): collection = db[coin] # Get last 100 data points, sorted by time cursor = ( collection.find({}, {"_id": 0, "timestamp": 1, "price": 1}) .sort("timestamp", -1) .limit(100) ) data = list(cursor) # Format the data for Chart.js times = [] prices = [] for item in reversed(data): # Reverse to show oldest to newest times.append(str(item["timestamp"])) prices.append(float(item["price"])) return {"times": times, "prices": prices} @app.get("/data/{coin}/get-candle/all") async def get_candle_data_all(coin): if coin in interest_coins: target = coin + "USDT" + "_kline" collection = db[target.lower()] latest_doc = collection.find_one(sort=[("T", -1)]) latest_end_time = latest_doc["T"] time_threshold = latest_end_time - ( 3000 ) # 60 seconds before the latest endTime pipeline = [ # Filter based on endTime {"$match": {"T": {"$gte": time_threshold}}}, # Group by start time and end time { "$group": { "_id": {"startTime": "$t", "endTime": "$T"}, "open": {"$first": "$o"}, "high": {"$max": "$h"}, "low": {"$min": "$l"}, "close": {"$last": "$c"}, "volume": {"$sum": "$v"}, "weighted_price": {"$sum": {"$multiply": ["$c", "$v"]}}, "count": {"$sum": 1}, } }, # Sort by start time {"$sort": {"_id.startTime": 1}}, # Reshape for output { "$project": { "_id": 0, "time": {"$multiply": ["$_id.startTime", 1000]}, "open": 1, "high": 1, "low": 1, "close": 1, "volume": 1, "vwap": { "$cond": { "if": {"$eq": ["$volume", 0]}, "then": 0, "else": {"$divide": ["$weighted_price", "$volume"]}, } }, "trades": "$count", "endTime": "$_id.endTime", } }, ] candles = list(collection.aggregate(pipeline)) return candles else: return None @app.get("/data/{coin}/get-candle") async def get_candle_data(coin): if coin in interest_coins: target = coin + "USDT" + "_kline" collection = db[target.lower()] latest_doc = collection.find_one(sort=[("T", -1)]) latest_end_time = latest_doc["T"] time_threshold = latest_end_time - (20) # 60 seconds before the latest endTime pipeline = [ # Filter based on endTime {"$match": {"T": {"$gte": time_threshold}}}, # Group by start time and end time { "$group": { "_id": {"startTime": "$t", "endTime": "$T"}, "open": {"$first": "$o"}, "high": {"$max": "$h"}, "low": {"$min": "$l"}, "close": {"$last": "$c"}, "volume": {"$sum": "$v"}, "weighted_price": {"$sum": {"$multiply": ["$c", "$v"]}}, "count": {"$sum": 1}, } }, # Sort by start time {"$sort": {"_id.startTime": 1}}, # Reshape for output { "$project": { "_id": 0, "time": {"$multiply": ["$_id.startTime", 1000]}, "open": 1, "high": 1, "low": 1, "close": 1, "volume": 1, "vwap": { "$cond": { "if": {"$eq": ["$volume", 0]}, "then": 0, "else": {"$divide": ["$weighted_price", "$volume"]}, } }, "trades": "$count", "endTime": "$_id.endTime", } }, ] candles = list(collection.aggregate(pipeline)) return candles[0] else: return None if __name__ == "__main__": uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)