diff options
author | lxf <sng@luxagraf.net> | 2022-01-06 10:01:13 -0500 |
---|---|---|
committer | lxf <sng@luxagraf.net> | 2022-01-06 10:01:13 -0500 |
commit | c2acb9c93081956725e33808764e35c61cc7b90b (patch) | |
tree | f1b9608d10cc20b6b99bff9a6e2c646804ab2133 | |
parent | f33fa7a87769a444acbc388037c0c71b3b7fc36a (diff) |
trad: started on simpler forms for updates and added profit to table
-rw-r--r-- | app/trading/admin.py | 4 | ||||
-rw-r--r-- | app/trading/forms.py | 23 | ||||
-rw-r--r-- | app/trading/migrations/0022_auto_20220104_1551.py | 22 | ||||
-rw-r--r-- | app/trading/models.py | 23 | ||||
-rw-r--r-- | app/trading/templates/trading/base.html | 2 | ||||
-rw-r--r-- | app/trading/templates/trading/create_luxoptions_form.html | 2 | ||||
-rw-r--r-- | app/trading/templates/trading/list.html | 2 | ||||
-rw-r--r-- | app/trading/templates/trading/luxoptions_update_form.html | 70 | ||||
-rw-r--r-- | app/trading/urls.py | 7 | ||||
-rw-r--r-- | app/trading/views.py | 48 |
10 files changed, 181 insertions, 22 deletions
diff --git a/app/trading/admin.py b/app/trading/admin.py index 3243f53..96e60ee 100644 --- a/app/trading/admin.py +++ b/app/trading/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin from django.db import models -from .models import TradeJrnl, LuxOptionsTrade, LuxTrade, LuxOptionPurchase, LuxOptionContact +from .models import TradeJrnl, LuxOptionsTrade, LuxTrade, LuxOptionPurchase, LuxOptionContract from utils.widgets import AdminImageWidget, LGEntryForm @@ -36,7 +36,7 @@ class LuxTradeAdmin(admin.ModelAdmin): class LuxOptionContactInline(admin.StackedInline): - model = LuxOptionContact + model = LuxOptionContract extra = 0 fieldsets = ( (None, { diff --git a/app/trading/forms.py b/app/trading/forms.py index 60c6de6..cd2128d 100644 --- a/app/trading/forms.py +++ b/app/trading/forms.py @@ -1,13 +1,13 @@ from django import forms from django.forms.utils import ValidationError -from .models import LuxOptionContact +from .models import LuxOptionContract class LuxOptionsForm(forms.ModelForm): contracts = forms.IntegerField() class Meta: - model = LuxOptionContact + model = LuxOptionContract fields = [ 'symbol', 'strike_price', @@ -17,9 +17,16 @@ class LuxOptionsForm(forms.ModelForm): 'contracts' ] - def save(self, commit=True): - i = 0 - while i < int(self.cleaned_data['contracts']): - print(i, "contracts") - i = i+1 - return super(LuxOptionsForm, self).save(commit=commit) + +class LuxOptionsUpdateForm(forms.ModelForm): + contracts_to_close = forms.IntegerField() + + class Meta: + model = LuxOptionContract + fields = [ + 'symbol', + 'strike_price', + 'expiration_date', + 'contracts_to_close', + 'contract_close_price', + ] diff --git a/app/trading/migrations/0022_auto_20220104_1551.py b/app/trading/migrations/0022_auto_20220104_1551.py new file mode 100644 index 0000000..f074f29 --- /dev/null +++ b/app/trading/migrations/0022_auto_20220104_1551.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.7 on 2022-01-04 15:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('trading', '0021_auto_20220104_1039'), + ] + + operations = [ + migrations.RenameModel( + old_name='LuxOptionContact', + new_name='LuxOptionContract', + ), + migrations.AlterField( + model_name='luxoptionpurchase', + name='status', + field=models.IntegerField(choices=[(0, 'Open'), (1, 'Closed')], default=0), + ), + ] diff --git a/app/trading/models.py b/app/trading/models.py index 720b834..d96970f 100644 --- a/app/trading/models.py +++ b/app/trading/models.py @@ -223,8 +223,21 @@ class LuxOptionPurchase(models.Model): 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.luxoptioncontact_set.count() + 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): @@ -232,7 +245,7 @@ class LuxOptionPurchase(models.Model): @property def total_invested(self): - return round(self.get_contract_count()*(self.luxoptioncontact_set.first().contract_open_price*100)) + return round(self.get_contract_count()*(self.luxoptioncontract_set.first().contract_open_price*100)) @property def trade_risk(self): @@ -244,11 +257,11 @@ class LuxOptionPurchase(models.Model): @property def sell_half_at(self): - return self.luxoptioncontact_set.first().contract_open_price*1.25 + return self.luxoptioncontract_set.first().contract_open_price*1.25 @property def contract_price(self): - return self.luxoptioncontact_set.first().contract_open_price + return self.luxoptioncontract_set.first().contract_open_price def save(self, *args, **kwargs): if self.status == 1 and not self.close_date: @@ -259,7 +272,7 @@ class LuxOptionPurchase(models.Model): super(LuxOptionPurchase, self).save() -class LuxOptionContact(models.Model): +class LuxOptionContract(models.Model): symbol = models.CharField(max_length=256) strike_price = models.FloatField() expiration_date = models.DateField() diff --git a/app/trading/templates/trading/base.html b/app/trading/templates/trading/base.html index 2d6e5da..9b9e6b0 100644 --- a/app/trading/templates/trading/base.html +++ b/app/trading/templates/trading/base.html @@ -15,7 +15,7 @@ <nav> <span class="nav-item"><a href="{% url 'luxtrade:list' %}">Home</a></span> <span class="nav-item"><a href="{% url 'luxtrade:testtrade' %}">Test Trade</a></span> - <span class="nav-item"><a href="{% url 'luxtrade:testoptions' %}">Test Options</a></span> + <span class="nav-item"><a href="{% url 'luxtrade:option-create' %}">Test Options</a></span> <span class="nav-item"><a href="https://wandererfinancial.com/{% now 'n-j-y'%}-todays-market/" target="_blank">Wanderer</a></span> <span class="nav-item"><a href="https://www.tradingview.com/chart/1a1NjVtp/" target="_blank">Trading View</a></span> <span class="nav-item"><a href="https://trade.tastyworks.com/index.html#/portfolioPage" target="_blank">Tastyworks</a></span> diff --git a/app/trading/templates/trading/create_luxoptions_form.html b/app/trading/templates/trading/create_luxoptions_form.html index 5fff0ae..937f90b 100644 --- a/app/trading/templates/trading/create_luxoptions_form.html +++ b/app/trading/templates/trading/create_luxoptions_form.html @@ -1,7 +1,7 @@ {% extends 'trading/base.html' %} {% load typogrify_tags %} {% block content %} - <form id="id_form" action="{% url 'luxtrade:testoptions' %}" method="post" class="big">{% csrf_token %} + <form id="id_form" action="{% url 'luxtrade:option-create' %}" method="post" class="big">{% csrf_token %} {% for field in form %} <fieldset> {{ field.errors }} diff --git a/app/trading/templates/trading/list.html b/app/trading/templates/trading/list.html index 3f6c3c0..be9b527 100644 --- a/app/trading/templates/trading/list.html +++ b/app/trading/templates/trading/list.html @@ -13,6 +13,7 @@ <th>% Portfolio Risk</th> <th>25% profit at</th> <th>Stop</th> + <th>Profit</th> <th>Notes</th> </tr> </thead> @@ -36,6 +37,7 @@ <td>{{object.portfolio_risk|floatformat:2}}%</td> <td>${{object.sell_half_at|floatformat:2}}</td> <td>${{object.stop_price|floatformat:2}}</td> + <td>${{object.profit_loss|floatformat:2}}</td> <td class="notes"> {% if object.notes %} <div class="wrapper"> diff --git a/app/trading/templates/trading/luxoptions_update_form.html b/app/trading/templates/trading/luxoptions_update_form.html new file mode 100644 index 0000000..14c80c3 --- /dev/null +++ b/app/trading/templates/trading/luxoptions_update_form.html @@ -0,0 +1,70 @@ +{% extends 'trading/base.html' %} +{% load typogrify_tags %} + {% block content %} + <form id="id_form" action="" method="post" class="big">{% csrf_token %} + {% for field in form %} + <fieldset> + {{ field.errors }} + {% if field.name == 'status' or field.name == 'call_put' %} + <label class="hide" for="id_status">Status:</label>{{ field }} + {% else %} + {% if field.name == 'strike_price' or field.name == 'expiration_date' %}<div class="hide">{%endif%} + {{ field.label_tag }} {{ field }} + {% if field.name == 'strike_price' or field.name == 'expiration_date' %}</div>{%endif%} + {% endif %} + {% if field.help_text %} + <p class="help">{{ field.help_text|safe }}</p> + {% endif %} + </fieldset> +{% endfor %} + <dl> + <dt>R/R: </dt><dd id="id_rr"></dd> + <dt>% Portfolio: </dt><dd id="id_p_portfolio"></dd> + <dt>Risk per contract: </dt><dd id="id_risk_contract"></dd> + <dt>Total Risk: </dt><dd id="id_risk_total"></dd> + <dt>Total Invested: </dt><dd id="id_total"></dd> + </dl> + <div class="flex"> + <input type="submit" name="post" class="btn" value="record purchase"/> + </div> + </form> + {% endblock %} + + {% block js %} +<script> +function calcPercentPortfolio() { + var entry_price = document.getElementById("id_entry_price").value; + var stop_price = document.getElementById("id_stop_price").value; + var target_price = document.getElementById("id_target_price").value; + var contract_price = document.getElementById("id_contract_price").value; + var number_contracts = document.getElementById("id_number_contracts").value; + var delta = document.getElementById("id_delta").value; + var pp = (contract_price*number_contracts)*100/10000; + var total = (contract_price*number_contracts)*100; + var rr = (target_price-entry_price)/(entry_price-stop_price); + var risk_per = ((entry_price-stop_price)*delta/contract_price)*contract_price*100 + var total_risk = (risk_per*number_contracts); + document.getElementById("id_p_portfolio").innerText = (pp*100).toFixed(2); + document.getElementById("id_risk_contract").innerText = "$"+risk_per.toFixed(2); + document.getElementById("id_risk_total").innerText = "$"+total_risk.toFixed(2); + document.getElementById("id_rr").innerText = rr.toFixed(2); + document.getElementById("id_total").innerText = "$"+total.toFixed(2); +} +id_form.addEventListener("input", function (e) { + calcPercentPortfolio(); +}); +var form = document.getElementById('id_form'); +function processForm(e) { + if (e.preventDefault) e.preventDefault(); + if(!confirm("Do you really want to do this?")) { + return false; + } + form.submit(); +} +if (form.attachEvent) { + form.attachEvent("submit", processForm); +} else { + form.addEventListener("submit", processForm); +} +</script> + {% endblock %} diff --git a/app/trading/urls.py b/app/trading/urls.py index 6bb486a..912e2c7 100644 --- a/app/trading/urls.py +++ b/app/trading/urls.py @@ -18,7 +18,12 @@ urlpatterns = [ path( 'options-calc', views.LuxOptionPurchaseCreateView.as_view(), - name='testoptions' + name='option-create' + ), + path( + 'trade/options/<pk>', + views.LuxOptionsPurchaseEditView.as_view(), + name='option-update' ), path( 'trade/options/<pk>', diff --git a/app/trading/views.py b/app/trading/views.py index b885d7c..69e1ace 100644 --- a/app/trading/views.py +++ b/app/trading/views.py @@ -3,8 +3,8 @@ from django.http import HttpResponseRedirect from django.views.generic.edit import CreateView, UpdateView from utils.views import PaginatedListView -from .models import LuxTrade, LuxOptionsTrade, LuxOptionContact, LuxOptionPurchase -from .forms import LuxOptionsForm +from .models import LuxTrade, LuxOptionsTrade, LuxOptionContract, LuxOptionPurchase +from .forms import LuxOptionsForm, LuxOptionsUpdateForm class LuxTradeListView(PaginatedListView): @@ -88,7 +88,7 @@ class OptionsModelFormView(CreateView): class LuxOptionPurchaseCreateView(CreateView): - model = LuxOptionContact + model = LuxOptionContract fields = ['symbol'] success_url = '/trading/' template_name = 'trading/create_luxoptions_form.html' @@ -108,7 +108,7 @@ class LuxOptionPurchaseCreateView(CreateView): ) print(form.cleaned_data['contracts']) while i < int(form.cleaned_data['contracts']): - c = LuxOptionContact.objects.create( + c = LuxOptionContract.objects.create( symbol = form.cleaned_data['symbol'], strike_price = form.cleaned_data['strike_price'], expiration_date = form.cleaned_data['expiration_date'], @@ -119,3 +119,43 @@ class LuxOptionPurchaseCreateView(CreateView): i = i+1 return HttpResponseRedirect('/trading/') return render(request, 'trading/create_luxoptions_form.html', {'form': form}) + +class LuxOptionsPurchaseEditView(UpdateView): + model = LuxOptionPurchase + fields = [ + 'symbol', + 'close_date', + 'status' + ] + success_url = '/trading/' + template_name = 'trading/luxoptions_update_form.html' + + + def get_context_data(self, **kwargs): + context = super(LuxOptionsPurchaseEditView, self).get_context_data(**kwargs) + obj = LuxOptionPurchase.objects.get(pk=self.object.pk) + context['form'] = LuxOptionsUpdateForm() + context['object'] = self.object + return context + + def post(self, request, *args, **kwargs): + form = LuxOptionsForm(request.POST) + if form.is_valid(): + i = 0 + p = LuxOptionPurchase.objects.get( + symbol = form.cleaned_data['symbol'], + open_date = form.cleaned_data['open_date'], + ) + print(form.cleaned_data['contracts_to_close']) + while i < int(form.cleaned_data['contracts_to_close']): + c = LuxOptionContract.objects.get( + symbol = form.cleaned_data['symbol'], + strike_price = form.cleaned_data['strike_price'], + expiration_date = form.cleaned_data['expiration_date'], + contract_open_price = form.cleaned_data['contract_open_price'], + call_put = form.cleaned_data['call_put'], + ) + c.contract_close_price = form.cleaned_data['contract_close_price'] + c.save() + return HttpResponseRedirect('/trading/') + return render(request, 'trading/create_luxoptions_form.html', {'form': form}) |