207 lines
6.6 KiB
Python
207 lines
6.6 KiB
Python
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)
|