I have created a simple app to keep track of stock trades. I have a value for each trade “entry” called pnl, which calculates the profit or loss based on the position size, openeing price and closing price. This function is all done within the Entry model.
I have verified that the code does execute properly and save the correct value to the “Pnl” field in the database. But for some reason you only see the new entry added to the table (entries.html) if you click the ‘back’ arrow on the browser. Even manually refreshing the page doesn’t do anything.
In fact, none of the entries show unless I clikc ‘Back’.
entries.html:
{% extends 'base.html' %}
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% block title %}
Trading Journal
{% endblock title %}Trading Journal
{% block content %}
<form method="POST" enctype="multipart/form-data" action="/">
{% csrf_token %}
{{ form }}
<button>Submit</button>
</form>
{% endblock content %}
{% block table %}
<table class="blueTable sortable">
<thead>
<tr>
<th>Date</th>
<th>Ticker</th>
<th>Strategy</th>
<th>Result</th>
<th>Open Price</th>
<th>Position</th>
<th>Closed Price</th>
<th>P&L</th>
<th>Comments</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="9">
<div class="links"><a href="#">«</a> <a class="active" href="#">1</a> <a href="#">2</a> <a href="#">3</a> <a href="#">4</a> <a href="#">»</a></div>
</td>
</tr>
</tfoot>
<tbody>
{% for entry in entries %}
<tr>
<td><a href="{% url 'single-entry' entry.id %}">{{entry.entered_date}}</a></td><td>{{entry.ticker}}</td><td>{{entry.strategy}}</td><td>{{entry.result}}</td><td>{{entry.open_price}}</td><td>{{entry.position}}</td><td>{{entry.close_price}}</td><td class="entry_pnl">{{entry.pnl}}</td><td>{{entry.comments}}</td></tr>
{% endfor %}
</tbody>
</tr>
</table>
{% if request.user.is_authenticated %}
<a href="{% url 'logout' %}"><button>Logout</button></a>
{% endif %}
{% endblock table %}
Views.py: (this shows the table with all entries as well as the form to enter a new Entry)
class EntryView(LoginRequiredMixin, View):
login_url = 'login'
def get(self, request):
logged_in_user = request.user.id
print("****************")
print(f'Logged in user:{logged_in_user}')
entries = Entry.objects.filter(trader_id=logged_in_user).order_by("entered_date") #see: https://docs.djangoproject.com/en/5.0/topics/db/queries/#field-lookups
form = EntryForm()
return render(request, "entries.html", {"form":form, "entries":entries, "user":logged_in_user})
def post(self, request):
form = EntryForm(request.POST, request.FILES) #must add request.FILES for uploads
if form.is_valid():
form.instance.trader = request.user #youre assigning one object to another; cant assign one object to a number. Or you could do trader_id on the LH side
form.instance.calculate_pnl()
form.save()
print('***************')
print(f"Entry pnl:{form.instance.pnl}")
return render(request, "entries.html")
else:
messages.error(request, "Please correct the errors below.")
return render(request, "entries.html", {"form":form})
Models.py:
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
from django.urls import reverse
from django.contrib.auth.models import User
class Entry(models.Model):
ONEORB="1-Min ORB"
FIVEORB="5-Min ORB"
ABCD="ABCD"
REVERSAL="Reversal"
PROFIT="Profit"
LOSS="Loss"
RESULT_CHOICES = (
(PROFIT, "Profit"),
(LOSS, "Loss")
)
STRATEGY_CHOICES = (
(ONEORB,"1-Min ORB"),
(FIVEORB,"5-Min ORB"),
(ABCD,"ABCD"),
(REVERSAL,"Reversal")
)
entered_date=models.DateField(auto_now_add=True)
ticker=models.CharField(max_length=8, default="")
strategy=models.CharField(max_length=12, choices=STRATEGY_CHOICES, default="ONEORB")
result=models.CharField(max_length=6, choices=RESULT_CHOICES, default="PROFIT")
comments=models.TextField(max_length=300, blank=True)
image = models.ImageField(upload_to="", null=True, blank=True) #will save to default BASE_DIR which is 'uploads'
position = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], blank=True, null=True)
open_price = models.DecimalField(max_digits=4, decimal_places=2, blank=True, null=True)
close_price = models.DecimalField(max_digits=4, decimal_places=2, blank=True, null=True)
pnl = models.DecimalField(max_digits=4, decimal_places=2, blank=True, null=True)
trader = models.ForeignKey(User, on_delete=models.CASCADE, blank=False, related_name="entries")
def calculate_pnl(self):
self.pnl = round(self.position * self.close_price - self.position * self.open_price, 2)
def __str__(self):
return f"{self.result} {self.entered_date}"
I tried commenting out the script tag which points to my following main.js file, which color codes the values based on if they are positive or negative. Didnt have any effect.
main.js:
document.addEventListener('DOMContentLoaded', function() {
let displayObj = document.querySelectorAll('.entry_pnl');
displayObj.forEach(function(el) {
// Parse the inner text of the '.entry_pnl' element to get the numerical value
let pnlValue = parseFloat(el.innerText);
if(pnlValue < 0) {
el.style.color = 'red';
} else {
el.style.color = 'green';
}
});
});