"""
Models here represents any interaction between a user and stocks
"""
from authentication.models import Profile
from django.db import models
from stocks.models import Stock, InvestmentBucket
[docs]class TradingAccount(models.Model):
"""
A TradingAccount is owned by a user, we associate stock trades with it.
"""
account_name = models.CharField(max_length=30)
profile = models.ForeignKey(Profile, related_name='trading_accounts')
class Meta(object):
unique_together = ('profile', 'account_name')
[docs] def holding_value(self):
"""
Calculates the value of all equity held by the user
"""
stock_values = sum([
Stock.objects.get(id=res['stock']).latest_quote() * res['q_s']
for res in
self.trades.values('stock').annotate(q_s=models.Sum('quantity'))
])
bucket_values = sum([
InvestmentBucket.objects.get(id=res['stock']).value_on() * res['q_s']
for res in
self.buckettrades.values('stock').annotate(q_s=models.Sum('quantity'))
])
return stock_values + bucket_values
[docs] def total_value(self):
"""
Total value of the trading account
"""
cash = self.available_cash()
stock_val = self.holding_value()
return cash + stock_val
[docs] def trading_balance(self):
"""
The stock values from account
"""
stock_val = sum([
stock.current_value()
for stock
in self.trades.all()
])
bucket_val = sum([
bucket.current_value()
for bucket
in self.buckettrades.all()
])
return stock_val + bucket_val
[docs] def available_buckets(self, bkt):
"""
Find the available buckets that have quantity > 0
"""
quantity = self.buckettrades.filter(stock=bkt).aggregate(sm=models.Sum('quantity'))['sm']
if not quantity:
quantity = 0
return quantity
[docs] def available_stocks(self, stk):
"""
Find available stock
"""
quantity = self.trades.filter(stock=stk).aggregate(sm=models.Sum('quantity'))['sm']
if not quantity:
quantity = 0
return quantity
[docs] def has_enough_cash(self, trade_value):
"""
Check if you have enough cash to make a trade
"""
if self.available_cash() >= trade_value:
return True
return False
[docs] def has_enough_bucket(self, bucket, quantity_bucket):
"""
Check if you have enough bucket to make a trade
"""
return self.available_buckets(bucket) >= quantity_bucket
[docs] def has_enough_stock(self, stock, quantity_stock):
"""
Check if you have enough stock to trade
"""
return self.available_stocks(stock) >= quantity_stock
[docs] def trade_bucket(self, bucket, quantity):
"""
Creates a new trade for the bucket and this account
"""
if self.has_enough_cash(bucket.value_on() * quantity) and (
self.has_enough_bucket(bucket, -1 * quantity)):
return self.buckettrades.create(
stock=bucket,
quantity=quantity,
)
raise Exception("You don't have the necessary resources!")
[docs] def trade_stock(self, stock, quantity):
"""
Trades a stock for the account
"""
if self.has_enough_cash(stock.latest_quote().value * quantity) and (
self.has_enough_stock(stock, -1 * quantity)):
return self.trades.create(
quantity=quantity,
stock=stock,
)
raise Exception("You don't have the necessary resources!")
[docs] def available_cash(self, update=True):
"""
Returns the available cash for the trading account
"""
return (
self.trading_balance() +
sum([
bnk.current_balance(update)
for bnk
in self.profile.user.userbank.all()
])
)
[docs]class TradeStock(models.Model):
"""
A Trade represents a single exchange of a stock for money
"""
timestamp = models.DateTimeField(auto_now_add=True)
quantity = models.FloatField()
account = models.ForeignKey(TradingAccount, related_name='trades')
stock = models.ForeignKey(Stock, related_name='trades')
[docs] def current_value(self):
"""
Get value calculates the total value of the trade respecting the date
"""
quote_value = self.stock.latest_quote(self.timestamp).value
return quote_value * (-1 * self.quantity)
[docs]class TradeBucket(models.Model):
"""
Same as trade but for buckets
"""
timestamp = models.DateTimeField(auto_now_add=True)
account = models.ForeignKey(TradingAccount, related_name='buckettrades')
stock = models.ForeignKey(InvestmentBucket, related_name='buckettrades')
quantity = models.FloatField()
[docs] def current_value(self):
"""
The value of the trade on the specific date
"""
val = self.stock.value_on(self.timestamp) * (-1 * self.quantity)
return val