SIP_GoldBees_Backend/strategy_code/paper_trading_yfinance.py
2026-02-01 13:13:41 +00:00

167 lines
4.6 KiB
Python

# =========================================================
# SIPXAR — PAPER TRADING (SESSION STATE ONLY)
# =========================================================
import math
import numpy as np
import pandas as pd
import yfinance as yf
import streamlit as st
from datetime import datetime
# =========================================================
# CONFIG
# =========================================================
MONTHLY_SIP = 10000
NIFTY = "NIFTYBEES.NS"
GOLD = "GOLDBEES.NS"
SMA_MONTHS = 36
BASE_EQUITY = 0.60
TILT_MULT = 1.5
MAX_TILT = 0.25
MIN_EQUITY = 0.20
MAX_EQUITY = 0.90
# =========================================================
# DATA
# =========================================================
@st.cache_data(ttl=300)
def fetch_price(ticker):
df = yf.download(
ticker,
period="5d",
interval="1d",
auto_adjust=True,
progress=False
)
return float(df["Close"].iloc[-1].item())
@st.cache_data(ttl=3600)
def fetch_sma(ticker):
df = yf.download(
ticker,
period=f"{SMA_MONTHS+2}mo",
interval="1mo",
auto_adjust=True,
progress=False
).dropna()
return float(df["Close"].tail(SMA_MONTHS).mean())
# =========================================================
# STRATEGY
# =========================================================
def compute_weights(n_price, g_price, n_sma, g_sma):
dev_n = (n_price / n_sma) - 1
dev_g = (g_price / g_sma) - 1
rel = dev_n - dev_g
tilt = np.clip(-rel * TILT_MULT, -MAX_TILT, MAX_TILT)
eq_w = BASE_EQUITY * (1 + tilt)
eq_w = min(max(eq_w, MIN_EQUITY), MAX_EQUITY)
return eq_w, 1 - eq_w
# =========================================================
# SESSION STATE INIT
# =========================================================
if "nifty_units" not in st.session_state:
st.session_state.nifty_units = 0
st.session_state.gold_units = 0
st.session_state.invested = 0
st.session_state.ledger = []
# =========================================================
# STREAMLIT UI
# =========================================================
st.set_page_config(page_title="SIPXAR Paper Trading", layout="centered")
st.title("📊 SIPXAR — Paper Trading (Session Only)")
# Fetch market data
n_price = fetch_price(NIFTY)
g_price = fetch_price(GOLD)
n_sma = fetch_sma(NIFTY)
g_sma = fetch_sma(GOLD)
eq_w, g_w = compute_weights(n_price, g_price, n_sma, g_sma)
# Market snapshot
st.subheader("Market Snapshot")
st.write(f"**NIFTY:** ₹{n_price:.2f}")
st.write(f"**GOLD:** ₹{g_price:.2f}")
# Allocation
st.subheader("Allocation Weights")
st.progress(eq_w)
st.write(f"Equity: **{eq_w:.2%}** | Gold: **{g_w:.2%}**")
# =========================================================
# SIP ACTION
# =========================================================
if st.button("Run Paper SIP (Once)"):
n_amt = MONTHLY_SIP * eq_w
g_amt = MONTHLY_SIP * g_w
n_qty = math.floor(n_amt / n_price)
g_qty = math.floor(g_amt / g_price)
if n_qty == 0 and g_qty == 0:
st.warning(
"SIP amount too small to buy ETF units at current prices."
)
else:
st.session_state.nifty_units += n_qty
st.session_state.gold_units += g_qty
st.session_state.invested += MONTHLY_SIP
port_value = (
st.session_state.nifty_units * n_price +
st.session_state.gold_units * g_price
)
st.session_state.ledger.append({
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"nifty_units": st.session_state.nifty_units,
"gold_units": st.session_state.gold_units,
"invested": st.session_state.invested,
"portfolio_value": port_value,
"pnl": port_value - st.session_state.invested
})
st.success("Paper SIP executed")
# =========================================================
# PORTFOLIO VIEW
# =========================================================
if st.session_state.invested > 0:
port_value = (
st.session_state.nifty_units * n_price +
st.session_state.gold_units * g_price
)
pnl = port_value - st.session_state.invested
st.subheader("Portfolio Summary")
st.metric("Total Invested", f"{st.session_state.invested:,.0f}")
st.metric("Portfolio Value", f"{port_value:,.0f}")
st.metric("PnL", f"{pnl:,.0f}")
df = pd.DataFrame(st.session_state.ledger)
st.subheader("Equity Curve")
st.line_chart(df[["portfolio_value", "invested"]])
st.subheader("Ledger")
st.dataframe(df, use_container_width=True)
else:
st.info("No SIPs yet. Click the button to start.")