feat: generate transaction records from snapshot diffs in seed script
All checks were successful
Deploy to Production / deploy (push) Successful in 1m27s

Derive buy/sell transactions by comparing consecutive snapshots and
replace existing portfolio on re-run instead of skipping.
This commit is contained in:
ayuriel 2026-02-16 20:56:12 +09:00
parent 48417a03f5
commit a899c17a65

View File

@ -8,7 +8,7 @@ Requires: DATABASE_URL environment variable or default dev connection.
"""
import sys
import os
from datetime import date
from datetime import date, datetime
from decimal import Decimal
# Add backend to path
@ -19,6 +19,7 @@ from app.core.database import SessionLocal
from app.models.portfolio import (
Portfolio, PortfolioType, Target, Holding,
PortfolioSnapshot, SnapshotHolding,
Transaction, TransactionType,
)
from app.models.user import User
@ -131,6 +132,17 @@ SNAPSHOTS = [
{"ticker": "411060", "qty": 328, "price": Decimal("29605"), "value": Decimal("9710440")},
],
},
{
"date": date(2026, 2, 16),
"total_assets": Decimal("62433665"),
"holdings": [
{"ticker": "069500", "qty": 16, "price": Decimal("81835"), "value": Decimal("1309360")},
{"ticker": "148070", "qty": 133, "price": Decimal("108290"), "value": Decimal("14402570")},
{"ticker": "284430", "qty": 1386, "price": Decimal("19250"), "value": Decimal("26680500")},
{"ticker": "360750", "qty": 385, "price": Decimal("24435"), "value": Decimal("9407475")},
{"ticker": "411060", "qty": 328, "price": Decimal("32420"), "value": Decimal("10633760")},
],
},
]
@ -142,14 +154,15 @@ def seed(db: Session):
print("ERROR: No user found in database. Create a user first.")
return
# Check if portfolio already exists
# Delete existing portfolio if present (cascade deletes related records)
existing = db.query(Portfolio).filter(
Portfolio.user_id == user.id,
Portfolio.name == "연금 포트폴리오",
).first()
if existing:
print(f"Portfolio '연금 포트폴리오' already exists (id={existing.id}). Skipping.")
return
db.delete(existing)
db.flush()
print(f"Deleted existing portfolio (id={existing.id})")
# Create portfolio
portfolio = Portfolio(
@ -189,6 +202,45 @@ def seed(db: Session):
))
print(f" Snapshot {snap['date']}: {len(snap['holdings'])} holdings")
# Create transactions by comparing consecutive snapshots
tx_count = 0
for i, snap in enumerate(SNAPSHOTS):
current_holdings = {h["ticker"]: h for h in snap["holdings"]}
if i == 0:
# First snapshot: all holdings are initial buys
prev_holdings = {}
else:
prev_holdings = {h["ticker"]: h for h in SNAPSHOTS[i - 1]["holdings"]}
all_tickers = set(current_holdings.keys()) | set(prev_holdings.keys())
for ticker in all_tickers:
cur_qty = current_holdings[ticker]["qty"] if ticker in current_holdings else 0
prev_qty = prev_holdings[ticker]["qty"] if ticker in prev_holdings else 0
diff = cur_qty - prev_qty
if diff == 0:
continue
if diff > 0:
tx_type = TransactionType.BUY
price = current_holdings[ticker]["price"]
else:
tx_type = TransactionType.SELL
price = prev_holdings[ticker]["price"]
db.add(Transaction(
portfolio_id=portfolio.id,
ticker=ticker,
tx_type=tx_type,
quantity=abs(diff),
price=price,
executed_at=datetime.combine(snap["date"], datetime.min.time()),
))
tx_count += 1
print(f"Created {tx_count} transactions from snapshot diffs")
# Set current holdings from latest snapshot
latest = SNAPSHOTS[-1]
for h in latest["holdings"]: