summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorluxagraf <sng@luxagraf.net>2021-07-14 09:31:15 -0400
committerluxagraf <sng@luxagraf.net>2021-07-14 09:31:15 -0400
commit39086b58106ff6181d029e0ef845593605821873 (patch)
treeb6652d1b74c1187eafbd0fbd74a3f00f4f1c9c58 /app
parentc2c0421207694aa5eb148f05a57440716ae2dc8d (diff)
trading: added trading to toolset
Diffstat (limited to 'app')
-rw-r--r--app/trading/admin.py57
-rw-r--r--app/trading/importer.py33
-rw-r--r--app/trading/migrations/0001_initial.py65
-rw-r--r--app/trading/migrations/0002_remove_luxtrademodel_percent_portfolio.py17
-rw-r--r--app/trading/migrations/0003_luxtrademodel_status.py18
-rw-r--r--app/trading/migrations/0004_rename_luxtrademodel_luxtrade.py17
-rw-r--r--app/trading/migrations/0005_auto_20210714_0747.py28
-rw-r--r--app/trading/migrations/0006_luxtrade_close_price.py18
-rw-r--r--app/trading/migrations/0007_alter_luxtrade_status.py18
-rw-r--r--app/trading/migrations/__init__.py0
-rw-r--r--app/trading/models.py174
-rw-r--r--app/trading/templates/products/snippet.html41
-rw-r--r--app/trading/templates/trading/base.html30
-rw-r--r--app/trading/templates/trading/create_form.html67
-rw-r--r--app/trading/templates/trading/list.html107
-rw-r--r--app/trading/templates/trading/update_form.html20
-rw-r--r--app/trading/urls.py24
-rw-r--r--app/trading/views.py43
18 files changed, 777 insertions, 0 deletions
diff --git a/app/trading/admin.py b/app/trading/admin.py
new file mode 100644
index 0000000..f95a272
--- /dev/null
+++ b/app/trading/admin.py
@@ -0,0 +1,57 @@
+from django.contrib import admin
+from markdownx.widgets import AdminMarkdownxWidget
+from django.db import models
+from .models import TradeJrnl, OptionsTrade
+from utils.widgets import AdminImageWidget, LGEntryForm
+
+
+@admin.register(TradeJrnl)
+class TradingJrnlAdmin(admin.ModelAdmin):
+ form = LGEntryForm
+ formfield_overrides = {
+ models.TextField: {'widget': AdminMarkdownxWidget},
+ }
+ class Media:
+ js = ('image-loader.js', 'next-prev-links.js')
+ css = {
+ "all": ("my_styles.css",)
+ }
+
+
+@admin.register(OptionsTrade)
+class OptionsTradeAdmin(admin.ModelAdmin):
+ list_display = ('symbol', 'date', 'buy_sell', 'open_close', 'quantity')
+ list_filter = ['buy_sell']
+ class Media:
+ js = ('image-loader.js', 'next-prev-links.js')
+ css = {
+ "all": ("my_styles.css",)
+ }
+
+"""
+ date = models.DateTimeField()
+ symbol = models.ForeignKey(Ticker, null=True, on_delete=models.SET_NULL)
+ TRANSACTION_CODE = (
+ ('Trade', 'Trade'),
+ )
+ transaction_code = models.CharField(choices=TRANSACTION_CODE, max_length=25)
+ TRANSACTION_SUBCODE = (
+ ('Buy to Open', 'Buy to Open'),
+ ('Sell to Open', 'Sell to Open'),
+ ('Sell to Close', 'Sell to Close'),
+ )
+ transaction_subcode = models.CharField(choices=TRANSACTION_SUBCODE, max_length=25)
+ open_close = models.CharField(choices=OPEN_CLOSE, max_length=5)
+ quantity = models.FloatField()
+ expiration_date = models.DateTimeField()
+ strike = models.FloatField()
+ CALL_PUT = (
+ ('C', 'Call'),
+ ('P', 'Put'),
+ )
+ call_put = models.CharField(choices=CALL_PUT, max_length=4)
+ price = models.FloatField()
+ fees = models.FloatField()
+ amount = models.FloatField()
+ description = models.TextField(blank=True)
+"""
diff --git a/app/trading/importer.py b/app/trading/importer.py
new file mode 100644
index 0000000..a975ff5
--- /dev/null
+++ b/app/trading/importer.py
@@ -0,0 +1,33 @@
+import csv
+from datetime import datetime
+
+from .models import Ticker
+
+with open(FILENAME, 'r' ) as theFile:
+ reader = csv.DictReader(theFile)
+ for line in reader:
+ dt = datetime.strptime(line['Date/Time'], '%m/%d/%Y %H:%M %p')
+ expiration_date = datetime.strptime(line['Expiration Date'], '%m/%d/%Y')
+ ticker, created = Ticker.objects.get_or_create(
+ symbol=line['Symbol']
+ )
+ print(ticker)
+ t, created = OptionsTrade.objects.get_or_create(
+ date=dt,
+ transaction_code=line['Transaction Code'],
+ transaction_subcode=line['Transaction Subcode'],
+ symbol=ticker,
+ buy_sell=line['Buy/Sell'],
+ open_close=line['Open/Close'],
+ quantity=int(line['Quantity']),
+ expiration_date = expiration_date,
+ strike = line['Strike'],
+ call_put = line['Call/Put'],
+ price = line['Price'],
+ fees = line['Fees'],
+ amount = line['Amount'],
+ description = line['Description']
+ )
+ if created:
+ print(t)
+
diff --git a/app/trading/migrations/0001_initial.py b/app/trading/migrations/0001_initial.py
new file mode 100644
index 0000000..54f8032
--- /dev/null
+++ b/app/trading/migrations/0001_initial.py
@@ -0,0 +1,65 @@
+# Generated by Django 3.2.4 on 2021-07-13 14:27
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='LuxTradeModel',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('symbol', models.CharField(max_length=256)),
+ ('date', models.DateTimeField(auto_now_add=True)),
+ ('entry_price', models.FloatField()),
+ ('stop_price', models.FloatField()),
+ ('target_price', models.FloatField()),
+ ('shares', models.FloatField()),
+ ('percent_portfolio', models.FloatField()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Ticker',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('symbol', models.CharField(max_length=9)),
+ ('name', models.CharField(blank=True, max_length=243, null=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='TradeJrnl',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('date', models.DateTimeField(auto_now_add=True)),
+ ('body_markdown', models.TextField(blank=True)),
+ ('body_html', models.TextField(blank=True, null=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='OptionsTrade',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('date', models.DateTimeField()),
+ ('transaction_code', models.CharField(choices=[('Trade', 'Trade')], max_length=25)),
+ ('transaction_subcode', models.CharField(choices=[('Buy to Open', 'Buy to Open'), ('Sell to Open', 'Sell to Open'), ('Sell to Close', 'Sell to Close')], max_length=25)),
+ ('buy_sell', models.CharField(choices=[('Buy', 'Buy'), ('Sell', 'Sell')], max_length=4)),
+ ('open_close', models.CharField(choices=[('Open', 'Open'), ('Close', 'Close')], max_length=5)),
+ ('quantity', models.FloatField()),
+ ('expiration_date', models.DateTimeField()),
+ ('strike', models.FloatField()),
+ ('call_put', models.CharField(choices=[('C', 'Call'), ('P', 'Put')], max_length=4)),
+ ('price', models.FloatField()),
+ ('fees', models.FloatField()),
+ ('amount', models.FloatField()),
+ ('description', models.TextField(blank=True)),
+ ('symbol', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='trading.ticker')),
+ ],
+ ),
+ ]
diff --git a/app/trading/migrations/0002_remove_luxtrademodel_percent_portfolio.py b/app/trading/migrations/0002_remove_luxtrademodel_percent_portfolio.py
new file mode 100644
index 0000000..b0dc82a
--- /dev/null
+++ b/app/trading/migrations/0002_remove_luxtrademodel_percent_portfolio.py
@@ -0,0 +1,17 @@
+# Generated by Django 3.2.4 on 2021-07-13 18:41
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('trading', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='luxtrademodel',
+ name='percent_portfolio',
+ ),
+ ]
diff --git a/app/trading/migrations/0003_luxtrademodel_status.py b/app/trading/migrations/0003_luxtrademodel_status.py
new file mode 100644
index 0000000..bd1b417
--- /dev/null
+++ b/app/trading/migrations/0003_luxtrademodel_status.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.4 on 2021-07-13 19:20
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('trading', '0002_remove_luxtrademodel_percent_portfolio'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='luxtrademodel',
+ name='status',
+ field=models.IntegerField(choices=[(0, 'Open'), (1, 'Closed')], default=0),
+ ),
+ ]
diff --git a/app/trading/migrations/0004_rename_luxtrademodel_luxtrade.py b/app/trading/migrations/0004_rename_luxtrademodel_luxtrade.py
new file mode 100644
index 0000000..bcb59d3
--- /dev/null
+++ b/app/trading/migrations/0004_rename_luxtrademodel_luxtrade.py
@@ -0,0 +1,17 @@
+# Generated by Django 3.2.4 on 2021-07-14 07:18
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('trading', '0003_luxtrademodel_status'),
+ ]
+
+ operations = [
+ migrations.RenameModel(
+ old_name='LuxTradeModel',
+ new_name='LuxTrade',
+ ),
+ ]
diff --git a/app/trading/migrations/0005_auto_20210714_0747.py b/app/trading/migrations/0005_auto_20210714_0747.py
new file mode 100644
index 0000000..bd54f71
--- /dev/null
+++ b/app/trading/migrations/0005_auto_20210714_0747.py
@@ -0,0 +1,28 @@
+# Generated by Django 3.2.4 on 2021-07-14 07:47
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('trading', '0004_rename_luxtrademodel_luxtrade'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='luxtrade',
+ name='close_date',
+ field=models.DateTimeField(blank=True, null=True),
+ ),
+ migrations.AddField(
+ model_name='luxtrade',
+ name='open_date',
+ field=models.DateTimeField(blank=True, null=True),
+ ),
+ migrations.AlterField(
+ model_name='luxtrade',
+ name='status',
+ field=models.IntegerField(choices=[(0, 'Open'), (1, 'Closed'), (2, 'Watching')], default=0),
+ ),
+ ]
diff --git a/app/trading/migrations/0006_luxtrade_close_price.py b/app/trading/migrations/0006_luxtrade_close_price.py
new file mode 100644
index 0000000..42f254d
--- /dev/null
+++ b/app/trading/migrations/0006_luxtrade_close_price.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.4 on 2021-07-14 08:22
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('trading', '0005_auto_20210714_0747'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='luxtrade',
+ name='close_price',
+ field=models.FloatField(blank=True, null=True),
+ ),
+ ]
diff --git a/app/trading/migrations/0007_alter_luxtrade_status.py b/app/trading/migrations/0007_alter_luxtrade_status.py
new file mode 100644
index 0000000..0566b17
--- /dev/null
+++ b/app/trading/migrations/0007_alter_luxtrade_status.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.4 on 2021-07-14 09:25
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('trading', '0006_luxtrade_close_price'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='luxtrade',
+ name='status',
+ field=models.IntegerField(choices=[(0, 'Open'), (1, 'Closed'), (2, 'Watching')], default=2),
+ ),
+ ]
diff --git a/app/trading/migrations/__init__.py b/app/trading/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/trading/migrations/__init__.py
diff --git a/app/trading/models.py b/app/trading/models.py
new file mode 100644
index 0000000..f9c9881
--- /dev/null
+++ b/app/trading/models.py
@@ -0,0 +1,174 @@
+import os
+from PIL import Image
+from django.db import models
+from django.db.models.signals import post_save
+from django.contrib.sitemaps import Sitemap
+from django.dispatch import receiver
+from django.urls import reverse
+from django.apps import apps
+from django.utils.html import format_html
+from django.utils import timezone
+from django.conf import settings
+from django.template.defaultfilters import slugify
+
+from media.models import LuxImage, LuxImageSize
+from media.utils import resize_image
+from utils.util import render_images, render_products, parse_video, markdown_to_html
+
+
+def get_upload_path(self, filename):
+ return "images/products/%s" % (filename)
+
+
+class Ticker(models.Model):
+ symbol = models.CharField(max_length=9)
+ name = models.CharField(max_length=243, blank=True, null=True)
+
+ def __str__(self):
+ return str(self.symbol)
+
+
+class OptionsTrade(models.Model):
+ date = models.DateTimeField()
+ symbol = models.ForeignKey(Ticker, null=True, on_delete=models.SET_NULL)
+ TRANSACTION_CODE = (
+ ('Trade', 'Trade'),
+ )
+ transaction_code = models.CharField(choices=TRANSACTION_CODE, max_length=25)
+ TRANSACTION_SUBCODE = (
+ ('Buy to Open', 'Buy to Open'),
+ ('Sell to Open', 'Sell to Open'),
+ ('Sell to Close', 'Sell to Close'),
+ )
+ transaction_subcode = models.CharField(choices=TRANSACTION_SUBCODE, max_length=25)
+ BUY_SELL = (
+ ('Buy', 'Buy'),
+ ('Sell', 'Sell'),
+ )
+ buy_sell = models.CharField(choices=BUY_SELL, max_length=4)
+ OPEN_CLOSE = (
+ ('Open', 'Open'),
+ ('Close', 'Close'),
+ )
+ open_close = models.CharField(choices=OPEN_CLOSE, max_length=5)
+ quantity = models.FloatField()
+ expiration_date = models.DateTimeField()
+ strike = models.FloatField()
+ CALL_PUT = (
+ ('C', 'Call'),
+ ('P', 'Put'),
+ )
+ call_put = models.CharField(choices=CALL_PUT, max_length=4)
+ price = models.FloatField()
+ fees = models.FloatField()
+ amount = models.FloatField()
+ description = models.TextField(blank=True)
+
+ def __str__(self):
+ return str(self.symbol)
+
+ def get_profit_by_symbol(self,t):
+ buy_amount = 0
+ sell_amount = 0
+ for o in OptionsTrade.objects.filter(symbol__symbol=t).filter(buy_sell="Sell"):
+ sell_amount+=o.amount+o.fees
+ for o in OptionsTrade.objects.filter(symbol__symbol=t).filter(buy_sell="Buy"):
+ buy_amount+=o.amount+o.fees
+ return buy_amount+sell_amount
+
+ def get_profit(self):
+ buy_amount = 0
+ sell_amount = 0
+ for o in OptionsTrade.objects.filter(buy_sell="Sell"):
+ sell_amount+=o.amount+o.fees
+ for o in OptionsTrade.objects.filter(buy_sell="Buy"):
+ buy_amount+=o.amount+o.fees
+ return buy_amount+sell_amount
+
+class LuxTrade(models.Model):
+ symbol = models.CharField(max_length=256)
+ date = models.DateTimeField(auto_now_add=True)
+ close_date = models.DateTimeField(null=True, blank=True)
+ open_date = models.DateTimeField(null=True, blank=True)
+ entry_price = models.FloatField()
+ stop_price = models.FloatField()
+ target_price = models.FloatField()
+ close_price = models.FloatField(null=True, blank=True)
+ shares = models.FloatField()
+ STATUS = (
+ (0, 'Open'),
+ (1, 'Closed'),
+ (2, 'Watching'),
+ )
+ status = models.IntegerField(choices=STATUS, default=2)
+
+ def __str__(self):
+ return str(self.symbol)
+
+ def get_absolute_url(self):
+ return reverse('luxtrade:detail', kwargs={"pk": self.pk})
+
+ @property
+ def risk_reward(self):
+ if self.stop_price > self.entry_price:
+ return "No risk"
+ else:
+ return (self.entry_price - self.stop_price)/(self.target_price-self.entry_price)
+
+ @property
+ def goal_dollars(self):
+ return (self.target_price*self.shares)-(self.entry_price*self.shares)
+
+ @property
+ def goal_percent(self):
+ return round((((self.target_price*self.shares)-(self.entry_price*self.shares))/self.amount_invested)*100, 2)
+
+ @property
+ def risk_dollars(self):
+ if self.stop_price > self.entry_price:
+ return 0
+ else:
+ return round((self.entry_price-self.stop_price)*self.shares, 2)
+
+ @property
+ def amount_invested(self):
+ return round(self.entry_price * self.shares, 2)
+
+ @property
+ def realized_dollars(self):
+ return (self.close_price*self.shares)-(self.entry_price*self.shares)
+
+ @property
+ def realized_percent(self):
+ return (self.realized_dollars/self.amount_invested)*100
+
+ def save(self, *args, **kwargs):
+ if self.status == 0 and not self.open_date:
+ self.open_date = timezone.now()
+ super(LuxTrade, self).save()
+
+class TradeJrnl(models.Model):
+ date = models.DateTimeField(auto_now_add=True)
+ body_markdown = models.TextField(blank=True)
+ body_html = models.TextField(null=True, blank=True)
+
+ def __str__(self):
+ return str(self.date)
+
+ @property
+ def get_previous_admin_url(self):
+ n = self.get_previous_by_read_date()
+ return reverse('admin:%s_%s_change' % (self._meta.app_label, self._meta.model_name), args=[n.id])
+
+ @property
+ def get_next_admin_url(self):
+ model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name)
+ try:
+ return reverse('admin:%s_%s_change' % (self._meta.app_label, self._meta.model_name), args=[self.get_next_by_read_date().pk])
+ except model.DoesNotExist:
+ return ''
+
+ def save(self, *args, **kwargs):
+ md = render_images(self.body_markdown)
+ self.body_html = markdown_to_html(md)
+ super(TradeJrnl, self).save()
diff --git a/app/trading/templates/products/snippet.html b/app/trading/templates/products/snippet.html
new file mode 100644
index 0000000..3fc9f6f
--- /dev/null
+++ b/app/trading/templates/products/snippet.html
@@ -0,0 +1,41 @@
+{% load get_image_by_size %}
+{% load get_image_width %}
+{% with image=object.featured_image %}
+<div itemscope itemtype="http://schema.org/Product" class="product-card">
+ <meta itemprop="brand" content="{{object.brand.name}}" />
+ <figure itemscope itemtype="http://schema.org/ImageObject" class="picfull">
+ <a href="{% get_image_by_size image 'original' %}" title="view larger image">
+ <img class="u-photo" itemprop="contentUrl" sizes="(max-width: 750px) 100vw, (min-width: 751) 750px" srcset="{% for size in image.sizes.all%}{% get_image_by_size image size.name %} {{size.width}}w{% if forloop.last%}"{%else%}, {%endif%}{%endfor%}{% for size in image.sizes.all%}{%if not forloop.first and not forloop.last%} src="{% get_image_by_size image size.name%}"{%endif%}{%endfor%} alt="{{image.alt}} photographed by {% if image.photo_credit_source %}{{image.photo_credit_source}}{%else%}luxagraf{%endif%}" >
+ </a>
+ <figcaption>{% if image.caption %}{{image.caption|safe}}{% endif %}{% if image.photo_credit_source %}{%if image.caption %} | {%endif%}image: {% if image.photo_credit_url %}<a href="{{image.photo_credit_url}}" itemprop="author">{%endif%}{{image.photo_credit_source|lower}}{% if image.photo_credit_url %}</a>{%endif%}{%endif%}
+ </figcaption>
+ </figure>
+ <div class="buy-btn-wrapper">
+ <h4 class="product-header" itemprop="name">{{object.get_full_name}}</h4>
+ <h5 class="product-link" itemprop="offers" itemscope itemtype="http://schema.org/Offer">
+ <a href="{{object.primary_offer_url}}" title="buy the {{object.get_full_name}} for ${{object.primary_offer_price}} from {{object.primary_offer_retailer.get_primary_offer_retailer_display}}" itemprop="url" rel="nofollow">
+ Buy Now ({{object.get_primary_offer_retailer_display}}
+ <span itemprop="priceCurrency" content="USD">$</span><span itemprop="price" content="{{object.primary_offer_price}}">{{object.primary_offer_price}}</span>)
+ </a>
+ <link itemprop="availability" href="http://schema.org/InStock" />
+ </h5>{% if object.secondary_offer_url %}
+ <h5 class="product-link" itemprop="offers" itemscope itemtype="http://schema.org/Offer">
+ <a href="{{object.secondary_offer_url}}" title="buy the {{object.get_full_name}} for ${{object.secondary_offer_price}} from {{object.secondary_offer_retailer.get_secondary_offer_retailer_display}}" itemprop="url">
+ Buy Now ({{object.get_secondary_offer_retailer_display}}
+ <span itemprop="priceCurrency" content="USD">$</span><span itemprop="price" content="{{object.secondary_offer_price}}">{{object.secondary_offer_price}}</span>)
+ </a>
+ <link itemprop="availability" href="http://schema.org/InStock" />
+ </h5>{% endif %}
+ </div>
+ <span itemprop="review" itemscope itemtype="http://schema.org/Review">
+ <meta itemprop="name" content="{{object.get_full_name}}" />
+ <meta itemprop="author" content="Scott Gilbertson" />
+ <meta itemprop="datePublished" content="{{object.pub_date}}" />
+ <span itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating">
+ <meta itemprop="worstRating" content = "1"/>
+ <meta itemprop="ratingValue" content="{{object.rating}}" />
+ <meta itemprop="bestRating" content="10" />
+ </span>
+ <meta itemprop="description" content="{{object.body_markdown}}" />
+</div>
+{% endwith %}
diff --git a/app/trading/templates/trading/base.html b/app/trading/templates/trading/base.html
new file mode 100644
index 0000000..86023ba
--- /dev/null
+++ b/app/trading/templates/trading/base.html
@@ -0,0 +1,30 @@
+<html>
+<head>
+ <title>{% block pagetitle %}Luxagraf - Topografical Writings{% endblock %}</title>
+ <meta charset="utf-8">
+ <meta http-equiv="x-ua-compatible" content="ie=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ {%block stylesheet%}<link rel="stylesheet"
+ href="/media/trading.css{%comment%}?{% now "u" %}{%endcomment%}"
+ media="screen">{%endblock%}
+ <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+ {%block extrahead%}{%endblock%}
+</head>
+ </head>
+ <body>
+ <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:testtrade' %}">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://client.schwab.com/Areas/Accounts/Positions" target="_blank">Schwab Positions</a></span>
+ <span class="nav-item"><a href="https://client.schwab.com/Areas/Trade/Stocks/Entry.aspx?" target="_blank">Schwab New Trade</a></span>
+ </nav>
+ {% block content %}
+ {% endblock %}
+ </body>
+ {% block js %}
+ {% endblock %}
+</html>
+
diff --git a/app/trading/templates/trading/create_form.html b/app/trading/templates/trading/create_form.html
new file mode 100644
index 0000000..521d420
--- /dev/null
+++ b/app/trading/templates/trading/create_form.html
@@ -0,0 +1,67 @@
+{% extends 'trading/base.html' %}
+{% load typogrify_tags %}
+ {% block content %}
+ <form id="id_form" action="/trading/model" method="post">{% csrf_token %}
+ {% for field in form %}
+ <fieldset>
+ {{ field.errors }}
+ {% if field.name == 'status'%}
+ <label class="hide" for="id_status">Status:</label>{{ field }}
+ {% else %}
+ {{ field.label_tag }} {{ field }}
+ {% endif %}
+ {% if field.help_text %}
+ <p class="help">{{ field.help_text|safe }}</p>
+ {% endif %}
+ </fieldset>
+{% endfor %}
+ <input type="submit" name="post" class="btn" value="record purchase"/>
+ </form>
+ <dl>
+ <dt>R/R: </dt><dd id="id_rr"></dd>
+ <dt>% Portfolio: </dt><dd id="id_p_portfolio"></dd>
+ <dt>Risk: </dt><dd id="id_risk"></dd>
+ <dt>Total Invested: </dt><dd id="id_total"></dd>
+ <dt>$ Goal: </dt><dd id="id_reward"></dd>
+ <dt>% Goal: </dt><dd id="id_reward_percent"></dd>
+ </dl>
+ {% 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 shares = document.getElementById("id_shares").value;
+ var pp = (entry_price*shares)/20000;
+ var risk_dollars = (entry_price-stop_price)*shares;
+ var goal = (target_price*shares)-(entry_price*shares);
+ var rr = (entry_price-stop_price)/(target_price-entry_price);
+ var total = entry_price*shares
+ var percent_goal = (goal/total)*100
+ document.getElementById("id_p_portfolio").innerText = (pp*100).toFixed(2);
+ document.getElementById("id_risk").innerText = "$"+risk_dollars.toFixed(2);
+ document.getElementById("id_reward").innerText = "$"+goal.toFixed(2);
+ document.getElementById("id_reward_percent").innerText = percent_goal.toFixed(0)+"%";
+ 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/templates/trading/list.html b/app/trading/templates/trading/list.html
new file mode 100644
index 0000000..fd754b6
--- /dev/null
+++ b/app/trading/templates/trading/list.html
@@ -0,0 +1,107 @@
+{% extends 'trading/base.html' %}
+ {% block content %}
+ <h3>Current Trades</h3>
+ <table>
+ <thead>
+ <tr>
+ <th>Open Date</th>
+ <th>Symbol</th>
+ <th>Entry Price</th>
+ <th>Stop</th>
+ <th>Target</th>
+ <th>Shares</th>
+ <th>Total Invested</th>
+ <th>$ at Risk</th>
+ <th>$ Goal</th>
+ <th>% Goal</th>
+ <th>Risk/Reward</th>
+ </tr>
+ </thead>
+ {% for object in open_trades %}
+ <tr>
+ <td><a href="{{object.get_absolute_url}}">{{object.date|date:"m-d-Y"}}</a></td>
+ <td>{{object.symbol}}</td>
+ <td>${{object.entry_price}}</td>
+ <td>${{object.stop_price}}</td>
+ <td>${{object.target_price}}</td>
+ <td>{{object.shares}}</td>
+ <td>${{object.amount_invested}}</td>
+ <td>${{object.risk_dollars}}</td>
+ <td>${{object.goal_dollars}}</td>
+ <td>{{object.goal_percent}}</td>
+ <td>{{object.risk_reward}}</td>
+ <td><input id="id_close_price"> <span id=profit"></span></td>
+ </tr>
+ {% endfor %}
+ </table>
+
+ <h3>Watching </h3>
+ <table>
+ <thead>
+ <tr>
+ <th>Open Date</th>
+ <th>Symbol</th>
+ <th>Entry Price</th>
+ <th>Stop</th>
+ <th>Target</th>
+ <th>Shares</th>
+ <th>Total Invested</th>
+ <th>$ at Risk</th>
+ <th>$ Goal</th>
+ <th>% Goal</th>
+ <th>Risk/Reward</th>
+ </tr>
+ </thead>
+ {% for object in watch_trades %}
+ <tr>
+ <td>{{object.date|date:"m-d-Y"}}</td>
+ <td>{{object.symbol}}</td>
+ <td>${{object.entry_price}}</td>
+ <td>${{object.stop_price}}</td>
+ <td>${{object.target_price}}</td>
+ <td>{{object.shares}}</td>
+ <td>${{object.amount_invested}}</td>
+ <td>${{object.risk_dollars}}</td>
+ <td>${{object.goal_dollars}}</td>
+ <td>{{object.goal_percent}}</td>
+ <td>{{object.risk_reward}}</td>
+ <td><input id="id_close_price"> <span id=profit"></span></td>
+ </tr>
+ {% endfor %}
+ </table>
+ <h3>Trade History</h3>
+ <table>
+ <thead>
+ <tr>
+ <th>Date Purchased</th>
+ <th>Symbol</th>
+ <th>Entry Price</th>
+ <th>Stop Price</th>
+ <th>Target Price</th>
+ <th>Number of Shares</th>
+ <th>Total Invested</th>
+ <th>$ at Risk</th>
+ <th>% at Risk</th>
+ <th>$ Goal</th>
+ <th>% Goal</th>
+ <th>Risk/Reward</th>
+ </tr>
+ </thead>
+ {% for object in object_list %}
+ <tr>
+ <td>{{object.date}}</td>
+ <td>{{object.symbol}}</td>
+ <td>${{object.entry_price}}</td>
+ <td>${{object.stop_price}}</td>
+ <td>${{object.target_price}}</td>
+ <td>{{object.shares}}</td>
+ <td>${{object.amount_invested}}</td>
+ <td>${{object.risk_dollars}}</td>
+ <td>{{object.risk_percent}}</td>
+ <td>${{object.goal_dollars}}</td>
+ <td>{{object.goal_percent}}</td>
+ <td>{{object.risk_reward}}</td>
+ </tr>
+ {% endfor %}
+ </table>
+ {% endblock %}
diff --git a/app/trading/templates/trading/update_form.html b/app/trading/templates/trading/update_form.html
new file mode 100644
index 0000000..01e0875
--- /dev/null
+++ b/app/trading/templates/trading/update_form.html
@@ -0,0 +1,20 @@
+{% extends 'trading/base.html' %}
+{% load typogrify_tags %}
+{% block content %}
+ <form id="id_form" action="" method="post">{% csrf_token %}
+ {% for field in form %}
+ <fieldset>
+ {{ field.errors }}
+ {% if field.name == 'status'%}
+ <label class="hide" for="id_status">Status:</label>{{ field }}
+ {% else %}
+ {{ field.label_tag }} {{ field }}
+ {% endif %}
+ {% if field.help_text %}
+ <p class="help">{{ field.help_text|safe }}</p>
+ {% endif %}
+ </fieldset>
+{% endfor %}
+ <input type="submit" name="post" class="btn" value="update trade"/>
+ </form>
+ {% endblock %}
diff --git a/app/trading/urls.py b/app/trading/urls.py
new file mode 100644
index 0000000..986339a
--- /dev/null
+++ b/app/trading/urls.py
@@ -0,0 +1,24 @@
+from django.urls import path, re_path
+
+from . import views
+
+app_name = "luxtrade"
+
+urlpatterns = [
+ path(
+ 'model',
+ views.TradeModelFormView.as_view(),
+ name='testtrade'
+ ),
+ path(
+ 'trade/<pk>',
+ views.LuxTradeDetailView.as_view(),
+ name='detail'
+ ),
+ path(
+ '',
+ views.LuxTradeListView.as_view(),
+ {'page':1},
+ name='list'
+ ),
+]
diff --git a/app/trading/views.py b/app/trading/views.py
new file mode 100644
index 0000000..a2bc5eb
--- /dev/null
+++ b/app/trading/views.py
@@ -0,0 +1,43 @@
+from django.shortcuts import render
+from django.views.generic.edit import FormView
+from django.views.generic.edit import CreateView, DeleteView, UpdateView
+from utils.views import PaginatedListView
+
+from .models import OptionsTrade, LuxTrade
+
+
+class OptionsTradeResultsView(PaginatedListView):
+ model = OptionsTrade
+
+ def get_context_data(self, **kwargs):
+ # Call the base implementation first to get a context
+ context = super(OptionsTradeResultsView, self).get_context_data(**kwargs)
+ return context
+
+class TradeModelFormView(CreateView):
+ model = LuxTrade
+ fields = ['symbol', 'status', 'entry_price', 'stop_price', 'target_price', 'shares']
+ success_url = '/trading/'
+ template_name = 'trading/create_form.html'
+
+class LuxTradeDetailView(UpdateView):
+ model = LuxTrade
+ fields = ['symbol', 'status', 'entry_price', 'stop_price', 'target_price', 'shares', 'close_price']
+ template_name = 'trading/update_form.html'
+ success_url = '/trading/'
+
+
+class LuxTradeListView(PaginatedListView):
+ model = LuxTrade
+ template_name = 'trading/list.html'
+
+ def get_context_data(self, **kwargs):
+ # Call the base implementation first to get a context
+ context = super(LuxTradeListView, self).get_context_data(**kwargs)
+ context['open_trades'] = LuxTrade.objects.filter(status=0)
+ context['watch_trades'] = LuxTrade.objects.filter(status=2)
+ return context
+
+ def get_queryset(self):
+ queryset = super(LuxTradeListView, self).get_queryset()
+ return queryset.filter(status=1)