70 lines
2.7 KiB
Python
70 lines
2.7 KiB
Python
from app.extensions import db
|
|
from datetime import datetime
|
|
|
|
|
|
class Investment(db.Model):
|
|
__tablename__ = 'investments'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
asset_name = db.Column(db.String(100), nullable=False)
|
|
ticker = db.Column(db.String(20), nullable=True)
|
|
asset_type = db.Column(
|
|
db.Enum('stock', 'etf', 'crypto', 'real_estate', 'bond', 'cash', 'other'),
|
|
nullable=False,
|
|
default='stock'
|
|
)
|
|
shares = db.Column(db.Numeric(18, 8), nullable=False, default=0)
|
|
avg_cost_basis = db.Column(db.Numeric(15, 4), nullable=False, default=0)
|
|
current_price = db.Column(db.Numeric(15, 4), nullable=True)
|
|
last_price_update = db.Column(db.DateTime, nullable=True)
|
|
notes = db.Column(db.Text, nullable=True)
|
|
is_active = db.Column(db.Boolean, default=True)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
inv_transactions = db.relationship('InvestmentTransaction', back_populates='investment',
|
|
lazy='dynamic', cascade='all, delete-orphan')
|
|
|
|
@property
|
|
def total_cost(self):
|
|
return float(self.shares) * float(self.avg_cost_basis)
|
|
|
|
@property
|
|
def current_value(self):
|
|
if self.current_price:
|
|
return float(self.shares) * float(self.current_price)
|
|
return self.total_cost
|
|
|
|
@property
|
|
def unrealized_gain(self):
|
|
return self.current_value - self.total_cost
|
|
|
|
@property
|
|
def unrealized_gain_pct(self):
|
|
if self.total_cost == 0:
|
|
return 0
|
|
return round((self.unrealized_gain / self.total_cost) * 100, 2)
|
|
|
|
def __repr__(self):
|
|
return f'<Investment {self.asset_name}>'
|
|
|
|
|
|
class InvestmentTransaction(db.Model):
|
|
__tablename__ = 'investment_transactions'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
investment_id = db.Column(db.Integer, db.ForeignKey('investments.id'), nullable=False)
|
|
transaction_type = db.Column(db.Enum('buy', 'sell', 'dividend', 'split'), nullable=False)
|
|
shares = db.Column(db.Numeric(18, 8), nullable=False)
|
|
price_per_share = db.Column(db.Numeric(15, 4), nullable=False)
|
|
total_amount = db.Column(db.Numeric(15, 2), nullable=False)
|
|
fees = db.Column(db.Numeric(10, 2), default=0.00)
|
|
date = db.Column(db.Date, nullable=False, index=True)
|
|
notes = db.Column(db.String(255), nullable=True)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
investment = db.relationship('Investment', back_populates='inv_transactions')
|
|
|
|
def __repr__(self):
|
|
return f'<InvTransaction {self.transaction_type} {self.shares}@{self.price_per_share}>'
|