Django model to save a stock portfolio to db

I’m trying to build a financial app in Django.

The goal of the app is: A user will have the ability to save a portfolio to the database, and the app will run different types of financial metrics on the data, as standard deviation, beta, alpha, ect…

The issue I’m facing is that the number of stocks a user has in their portfolio is different for each user. A user who is a risk-averse investor would maybe have ten stocks, while an investor who is trading in the short term might only have 2-3 stocks in the portfolio.

Each transaction consists of 5 elements: the direction the user has traded, either “long” or “short.” The ticker, volume of the trade, price paid, and the transaction date.

So, for example, a user has three stocks the transactions would look something like this: Transaction example

How can I give the user the ability to choose how many stocks they would like to record in the portfolio?

My code:

models.py

    from django.db import models
    from django.contrib.auth.models import User
    from django.conf import settings

    class Portfolio(models.Model):
        direction_option = (
            ('Long','Long'),
            ('Short','Short')
        )

        portfolio_name = models.CharField(max_length=200)
        user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True)

        direction = models.CharField(max_length=200, null=True, choices=direction_option)
        ticker = models.CharField(max_length=10, null=True)
        volume = models.CharField(max_length=10, null=True)
        price = models.FloatField(null=True)
        transaction_date = models.DateField(null=True)

        def __str__(self):
            return self.portfolio_name

Forms.py

from django import forms
from django.forms import ModelForm
from .models import *

class DateInput(forms.DateInput):
    input_type = 'date'

class PortfolioForm(ModelForm):
    class Meta:
        model = Portfolio
        fields = ['portfolio_name','direction','ticker','volume','price','transaction_date']
        widgets = {
            'transaction_date':DateInput(),
        }

Views.py

from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from .forms import PortfolioForm
from .models import Portfolio
from django.contrib.auth.models import User

@login_required
def portfolio(request):

    form = PortfolioForm()
    if request.method == 'POST':
        #print('Printing post', request.POST)
        form = PortfolioForm(request.POST)


        if form.is_valid():
            instace = form.save(commit=False)
            instace.user = request.user
            instace.save()
            #form.save()
            return redirect('../')

    context = {'form' : form}

    return render(request, 'backapp/portfolio.html', context)

FYI: I’m a little new to Django.

Taking the simplified view, if I were starting this from scratch and needed to build a set of models, I might start with an approach that begins to look like this:
(Greatly simplified and somewhat abstracted…)

class Portfolio(models.Model):
    user = modelsForeignKey('User',...)
    <other portfolio specific information>

class Stock(models.Model):
    ticker = models.CharField(...)
    portfolio = models.ForeignKey('Portfolio', ...)

class Transaction(models.Model):
    stock = models.ForeignKey('Stock')
    <other transaction specific data>

Now, I’d want to identify whether or not a User can have more than one Portfolio. (I know that’s true in the real world, I have no idea whether or not that applies in your app.) If there is a One-to-One relationship between User and Portfolio, that’s how I would define it in the Portfolio, not as a Foreign Key.

But, beyond that, the basic idea here is that a Portfolio is a collection of stocks. But each stock may have multiple transactions associated with that stock.

In the traditional investment model, the Portfolio is your collection of investments, it’s not the set of transactions that add / remove investments from that portfolio.

And, depending upon specific needs, I may consider denormalizing the Stock table to contain a current count of number of shares owned. But, under most situations, I wouldn’t do that. I’d rely upon the database engine to calculate that from the Transaction table on the fly. If I had more detailed reporting requirements for something like that, I’d calculate as-of-date reporting values and store them in a “BI” tool for accounting and reporting.

Ken

1 Like

Thanks for the response Ken,

If i would describe the portfolio as a dictionary, it would look like this:

portfolios = {
    "user1":{
        
        "portfolio1":{
            "portfolio name":"Long term",
            "risk":"medium",
            "return":"medium",
            "transactions":{
                "trans1":{
                    "Direction":"long",
                    "Ticker":"TSLA",
                    "Volume":500,
                    "Price":900.23
                    },
                "trans2":{
                    "Direction":"Short",
                    "Ticker":"AMZN",
                    "Volume":500,
                    "Price":900.23
                    },
                "trans3":{
                    "Direction":"Short",
                    "Ticker":"AMZN",
                    "Volume":200,
                    "Price":900.23
                    }
                }
            },
        
        "portfolio2":{
            "portfolio name":"Short term",
            "risk":"High",
            "return":"High",
            "transactions":{
                "trans1":{
                    "Direction":"Short",
                    "Ticker":"TSLA",
                    "Volume":500,
                    "Price":900.23
                    },
                "trans2":{
                    "Direction":"Short",
                    "Ticker":"AMZN",
                    "Volume":500,
                    "Price":900.23
                    }
                }
            },
        
        "portfolio3":{
            "portfolio name":"Gambling",
            "risk":"High",
            "return":"High",
            "transactions":{
                "trans1":{
                    "Direction":"Short",
                    "Ticker":"TSLA",
                    "Volume":500,
                    "Price":900.23
                    }
                }
            }
        },
    
    "user2":{
        "portfolio1":{
            "portfolio name":"My portfolio",
            "risk":"medium",
            "return":"medium",
            "transactions":{
                "trans1":{
                    "Direction":"long",
                    "Ticker":"TSLA",
                    "Volume":500,
                    "Price":900.23
                    },
                "trans2":{
                    "Direction":"Short",
                    "Ticker":"AMZN",
                    "Volume":500,
                    "Price":900.23
                    },
                "trans3":{
                    "Direction":"Short",
                    "Ticker":"AMZN",
                    "Volume":200,
                    "Price":900.23
                    },
                "trans4":{
                    "Direction":"Short",
                    "Ticker":"NFLX",
                    "Volume":200,
                    "Price":900.23
                    }
                }
            }
        }
    
    }

In this example a user can have multiple portfolios, and have diffrent range of transactions in a portfolio.

So by following your reccomendation, my model will look something like this:

from django.db import models
from django.contrib.auth.models import User
from django.conf import settings

class Portfolio(models.Model):
    risk_options = (
        ('Low','Low'),
        ('Low medium','Low medium'),
        ('Medium','Medium'),
        ('Medium high', 'Medium high'),
        ('High', 'High')
    )

    portfolio_name = models.CharField(max_length=200)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True)

    risk = models.CharField(max_length=200, null=True, choices=risk_options)
    expected_return = models.FloatField(null=True)
    currency = models.CharField(max_length=10, null=True)
    investment_horizion = models.DateField(null=True)

    def __str__(self):
        return self.portfolio_name

class Transactions(models.Model):
    direction_options = (
        ('Long','Long'),
        ('Sell','Sell'),
        ('Short','Short')
    )
    portfolio = models.ForeignKey('Portfolio', on_delete=models.CASCADE)

    direction = models.CharField(max_length=200, null=True, choices=direction_options)
    ticker = models.CharField(max_length=10, null=True)
    volume = models.IntegerField(null=True)
    price = models.FloatField(null=True)
    transaction_date = models.DateField(null=True)

Would that be correct, and how will my forms view look? How can a user input multiple transactions?

If you’re looking at allowing a user to enter multiple entries of the same “type” on a page, you’re looking for Django’s formset facility.

1 Like