commit - mock buy
This commit is contained in:
Binary file not shown.
BIN
backend/app/api/__pycache__/portfolio.cpython-313.pyc
Normal file
BIN
backend/app/api/__pycache__/portfolio.cpython-313.pyc
Normal file
Binary file not shown.
102
backend/app/api/portfolio.py
Normal file
102
backend/app/api/portfolio.py
Normal file
@@ -0,0 +1,102 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
from pydantic import BaseModel
|
||||
import yfinance as yf
|
||||
from app.db.database import get_db
|
||||
from app.db.models import User, PortfolioItem
|
||||
from app.api.auth import get_current_user
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
class BuyRequest(BaseModel):
|
||||
symbol: str
|
||||
quantity: int
|
||||
buy_price: float
|
||||
|
||||
class SellRequest(BaseModel):
|
||||
portfolio_item_id: int
|
||||
|
||||
@router.post("/buy")
|
||||
def buy_stock(req: BuyRequest, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)):
|
||||
final_buy_price = req.buy_price
|
||||
|
||||
# If price wasn't provided (e.g. from watchlist), fetch it live
|
||||
if final_buy_price <= 0:
|
||||
try:
|
||||
ticker = yf.Ticker(req.symbol)
|
||||
final_buy_price = ticker.fast_info.last_price
|
||||
except Exception as e:
|
||||
print(f"Error fetching live price on buy for {req.symbol}: {e}")
|
||||
raise HTTPException(status_code=400, detail="Could not fetch live price, please try again.")
|
||||
|
||||
new_item = PortfolioItem(
|
||||
user_id=current_user.id,
|
||||
symbol=req.symbol,
|
||||
quantity=req.quantity,
|
||||
buy_price=final_buy_price
|
||||
)
|
||||
db.add(new_item)
|
||||
db.commit()
|
||||
db.refresh(new_item)
|
||||
return {"message": "Stock purchased successfully", "item": new_item}
|
||||
|
||||
@router.get("/")
|
||||
def get_portfolio(db: Session = Depends(get_db), current_user: User = Depends(get_current_user)):
|
||||
items = db.query(PortfolioItem).filter(PortfolioItem.user_id == current_user.id).all()
|
||||
|
||||
portfolio = []
|
||||
total_invested = 0
|
||||
total_current_value = 0
|
||||
|
||||
for item in items:
|
||||
# Fetch live price
|
||||
live_price = item.buy_price # Fallback
|
||||
try:
|
||||
ticker = yf.Ticker(item.symbol)
|
||||
live_price = ticker.fast_info.last_price
|
||||
except Exception as e:
|
||||
print(f"Error fetching price for {item.symbol}: {e}")
|
||||
|
||||
invested = item.quantity * item.buy_price
|
||||
current_value = item.quantity * live_price
|
||||
pnl = current_value - invested
|
||||
pnl_percent = (pnl / invested) * 100 if invested > 0 else 0
|
||||
|
||||
total_invested += invested
|
||||
total_current_value += current_value
|
||||
|
||||
portfolio.append({
|
||||
"id": item.id,
|
||||
"symbol": item.symbol,
|
||||
"quantity": item.quantity,
|
||||
"buy_price": item.buy_price,
|
||||
"current_price": round(live_price, 2),
|
||||
"invested": round(invested, 2),
|
||||
"current_value": round(current_value, 2),
|
||||
"pnl": round(pnl, 2),
|
||||
"pnl_percent": round(pnl_percent, 2),
|
||||
"purchase_date": item.purchase_date
|
||||
})
|
||||
|
||||
total_pnl = total_current_value - total_invested
|
||||
total_pnl_percent = (total_pnl / total_invested) * 100 if total_invested > 0 else 0
|
||||
|
||||
return {
|
||||
"items": portfolio,
|
||||
"summary": {
|
||||
"total_invested": round(total_invested, 2),
|
||||
"total_current_value": round(total_current_value, 2),
|
||||
"total_pnl": round(total_pnl, 2),
|
||||
"total_pnl_percent": round(total_pnl_percent, 2)
|
||||
}
|
||||
}
|
||||
|
||||
@router.delete("/{item_id}")
|
||||
def delete_portfolio_item(item_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)):
|
||||
item = db.query(PortfolioItem).filter(PortfolioItem.id == item_id, PortfolioItem.user_id == current_user.id).first()
|
||||
if not item:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
|
||||
db.delete(item)
|
||||
db.commit()
|
||||
return {"message": "Stock sold/removed successfully"}
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
|
||||
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:M%40triXPostgr3s%406202@host.docker.internal:5333/stock_scanner")
|
||||
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:M%40triXPostgr3s%406202@192.168.0.111:5432/stock_scanner")
|
||||
SECRET_KEY = "stock-scanner-super-secret-key-12345"
|
||||
ALGORITHM = "HS256"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = 60
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,6 @@
|
||||
from sqlalchemy import Column, Integer, String, JSON
|
||||
from sqlalchemy import Column, Integer, String, JSON, Float, ForeignKey, DateTime
|
||||
from app.db.database import Base
|
||||
import datetime
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
@@ -12,3 +13,13 @@ class User(Base):
|
||||
mobile_no = Column(String, nullable=True)
|
||||
gender = Column(String, nullable=True)
|
||||
sector_map = Column(JSON, nullable=True)
|
||||
|
||||
class PortfolioItem(Base):
|
||||
__tablename__ = "portfolio_items"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"))
|
||||
symbol = Column(String, index=True)
|
||||
quantity = Column(Integer, default=1)
|
||||
buy_price = Column(Float)
|
||||
purchase_date = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from app.api import auth, scanner
|
||||
from app.api import auth, scanner, portfolio
|
||||
from app.db.database import engine, Base
|
||||
|
||||
# Initialize the database tables
|
||||
@@ -20,6 +20,7 @@ app.add_middleware(
|
||||
# Include Routers
|
||||
app.include_router(auth.router, prefix="/api/auth", tags=["auth"])
|
||||
app.include_router(scanner.router, prefix="/api/scanner", tags=["scanner"])
|
||||
app.include_router(portfolio.router, prefix="/api/portfolio", tags=["portfolio"])
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
|
||||
Reference in New Issue
Block a user