From 1b74c74fb154385d861d8a74feca75826d1c8a4b Mon Sep 17 00:00:00 2001 From: lxf Date: Thu, 6 Jan 2022 10:28:50 -0500 Subject: trad: added monthly and yearly options stats plus color to tables --- app/trading/models.py | 186 +++++++++++++++++--------------- app/trading/templates/trading/list.html | 29 ++++- app/trading/views.py | 6 +- 3 files changed, 134 insertions(+), 87 deletions(-) diff --git a/app/trading/models.py b/app/trading/models.py index d96970f..10aaaf4 100644 --- a/app/trading/models.py +++ b/app/trading/models.py @@ -205,90 +205,6 @@ class LuxOptionsTradeStatsManager(models.Manager): return self.filter(close_date__range=(start_date, end_date)).aggregate(Sum('pl')) -class LuxOptionPurchase(models.Model): - symbol = models.CharField(max_length=256) - open_date = models.DateTimeField(auto_now_add=True) - close_date = models.DateTimeField(null=True, blank=True) - pl = models.FloatField(null=True, blank=True) - STATUS = ( - (0, 'Open'), - (1, 'Closed'), - ) - status = models.IntegerField(choices=STATUS, default=0) - - class Meta: - ordering = ('-open_date',) - get_latest_by = 'open_date' - - def __str__(self): - return str(self.symbol) - - def get_absolute_url(self): - return reverse('luxtrade:option-update', kwargs={"pk": self.pk}) - - def get_contract_count(self): - return self.luxoptioncontract_set.count() - - def profit_loss(self): - total = 0 - for option in self.luxoptioncontract_set.all(): - if option.contract_close_price: - pl = option.contract_close_price - option.contract_open_price - else: - pl = 0 - total = total + pl - return total*100 - - @property - def stop_price(self): - return (self.contract_price*.75) - - @property - def total_invested(self): - return round(self.get_contract_count()*(self.luxoptioncontract_set.first().contract_open_price*100)) - - @property - def trade_risk(self): - return round(self.total_invested*.25) - - @property - def portfolio_risk(self): - return (self.trade_risk/10000)*100 - - @property - def sell_half_at(self): - return self.luxoptioncontract_set.first().contract_open_price*1.25 - - @property - def contract_price(self): - return self.luxoptioncontract_set.first().contract_open_price - - def save(self, *args, **kwargs): - if self.status == 1 and not self.close_date: - self.close_date = timezone.now() - if self.status == 1 and not self.pl: - pass - #self.pl = round((self.close_price*self.shares)-(self.entry_price*self.shares), 2) - super(LuxOptionPurchase, self).save() - - -class LuxOptionContract(models.Model): - symbol = models.CharField(max_length=256) - strike_price = models.FloatField() - expiration_date = models.DateField() - contract_open_price = models.FloatField() - contract_close_price = models.FloatField(null=True, blank=True) - CALL_PUT = ( - (0, 'Calls'), - (1, 'Puts'), - ) - call_put = models.IntegerField(choices=CALL_PUT, default=0) - options_purchase = models.ForeignKey(LuxOptionPurchase, null=True, on_delete=models.SET_NULL) - - def __str__(self): - return "%s - %s %s" %(self.symbol, round(self.strike_price), self.get_call_put_display()) - - class LuxOptionsTrade(models.Model): symbol = models.CharField(max_length=256) date = models.DateTimeField(auto_now_add=True) @@ -432,3 +348,105 @@ class TradeJrnl(models.Model): md = render_images(self.body_markdown) self.body_html = markdown_to_html(md) super(TradeJrnl, self).save() + + +class LuxOptionsPurchaseStatsManager(models.Manager): + + def get_month_pl(self, month=timezone.now().month): + last_day = calendar.monthrange(timezone.now().year, month)[1] + start_date = datetime.date(timezone.now().year, month, 1) + end_date = datetime.date(timezone.now().year, month, last_day) + return self.filter(close_date__range=(start_date, end_date)).aggregate(Sum('pl')) + + def get_year_pl(self, year=timezone.now().year): + start_date = datetime.date(year, 1, 1) + end_date = datetime.date(year, 12, 31) + return self.filter(close_date__range=(start_date, end_date)).aggregate(Sum('pl')) + + +class LuxOptionPurchase(models.Model): + symbol = models.CharField(max_length=256) + open_date = models.DateTimeField(auto_now_add=True) + close_date = models.DateTimeField(null=True, blank=True) + pl = models.FloatField(null=True, blank=True) + STATUS = ( + (0, 'Open'), + (1, 'Closed'), + ) + status = models.IntegerField(choices=STATUS, default=0) + + class Meta: + ordering = ('-open_date',) + get_latest_by = 'open_date' + + objects = models.Manager() # The default manager. + stats = LuxOptionsPurchaseStatsManager() + + def __str__(self): + return str(self.symbol) + + def get_absolute_url(self): + return reverse('luxtrade:option-update', kwargs={"pk": self.pk}) + + def get_contract_count(self): + return self.luxoptioncontract_set.count() + + def profit_loss(self): + total = 0 + for option in self.luxoptioncontract_set.all(): + if option.contract_close_price: + pl = option.contract_close_price - option.contract_open_price + else: + pl = 0 + total = total + pl + return total*100 + + @property + def stop_price(self): + return (self.contract_price*.75) + + @property + def total_invested(self): + return round(self.get_contract_count()*(self.luxoptioncontract_set.first().contract_open_price*100)) + + @property + def trade_risk(self): + return round(self.total_invested*.25) + + @property + def portfolio_risk(self): + return (self.trade_risk/10000)*100 + + @property + def sell_half_at(self): + return self.luxoptioncontract_set.first().contract_open_price*1.25 + + @property + def contract_price(self): + return self.luxoptioncontract_set.first().contract_open_price + + def save(self, *args, **kwargs): + if self.status == 1 and not self.close_date: + self.close_date = timezone.now() + if self.status == 1 and not self.pl: + self.pl = self.profit_loss + super(LuxOptionPurchase, self).save() + + +class LuxOptionContract(models.Model): + symbol = models.CharField(max_length=256) + strike_price = models.FloatField() + expiration_date = models.DateField() + contract_open_price = models.FloatField() + contract_close_price = models.FloatField(null=True, blank=True) + CALL_PUT = ( + (0, 'Calls'), + (1, 'Puts'), + ) + call_put = models.IntegerField(choices=CALL_PUT, default=0) + options_purchase = models.ForeignKey(LuxOptionPurchase, null=True, on_delete=models.SET_NULL) + + def __str__(self): + return "%s - %s %s" %(self.symbol, round(self.strike_price), self.get_call_put_display()) + + diff --git a/app/trading/templates/trading/list.html b/app/trading/templates/trading/list.html index a8a0a01..d89504a 100644 --- a/app/trading/templates/trading/list.html +++ b/app/trading/templates/trading/list.html @@ -37,7 +37,7 @@ {{object.portfolio_risk|floatformat:2}}% ${{object.sell_half_at|floatformat:2}} ${{object.stop_price|floatformat:2}} - ${{object.profit_loss|floatformat:2}} + 0 %}class="money"{%elif object.profit_loss < 0 %}class="nomoney"{%endif%}>${{object.profit_loss|floatformat:2}} {% if object.notes %}
@@ -50,6 +50,33 @@ {% endif %} {% endfor %} + +   + + + + + + + + + + {{month}} P/L: + {{monthly_pl.pl__sum}} + + + + + + + + + + + YTD P/L: + {{year_pl.pl__sum}} + + {% comment %}

Options Trades

diff --git a/app/trading/views.py b/app/trading/views.py index 69e1ace..982fb8f 100644 --- a/app/trading/views.py +++ b/app/trading/views.py @@ -20,8 +20,10 @@ class LuxTradeListView(PaginatedListView): context['options_trades_closed'] = LuxOptionsTrade.objects.filter(status=1) context['monthly_pl'] = LuxTrade.stats.get_month_pl() context['year_pl'] = LuxTrade.stats.get_year_pl() - context['options_monthly_pl'] = LuxOptionsTrade.stats.get_month_pl() - context['options_year_pl'] = LuxOptionsTrade.stats.get_year_pl() + #context['options_monthly_pl'] = LuxOptionsTrade.stats.get_month_pl() + #context['options_year_pl'] = LuxOptionsTrade.stats.get_year_pl() + context['options_monthly_pl'] = LuxOptionPurchase.stats.get_month_pl() + context['options_year_pl'] = LuxOptionPurchase.stats.get_year_pl() context['month'] = datetime.now().strftime('%h') context['luxoptions_purchases'] = LuxOptionPurchase.objects.filter(status=0) return context -- cgit v1.2.3-70-g09d2