├── README.md └── paper_trading ├── accounts ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-39.pyc │ ├── admin.cpython-39.pyc │ ├── apps.cpython-39.pyc │ ├── models.cpython-39.pyc │ └── views.cpython-39.pyc ├── admin.py ├── apps.py ├── migrations │ ├── __init__.py │ └── __pycache__ │ │ └── __init__.cpython-39.pyc ├── models.py ├── templates │ ├── account_settings.html │ ├── change_password.html │ ├── portfolio.html │ └── signup.html ├── tests.py └── views.py ├── manage.py ├── paper_trading ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-39.pyc │ ├── settings.cpython-39.pyc │ ├── urls.cpython-39.pyc │ └── wsgi.cpython-39.pyc ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py ├── requirements.txt ├── templates ├── base.html ├── foreign_base.html └── registration │ └── login.html └── trader ├── __init__.py ├── __pycache__ ├── __init__.cpython-39.pyc ├── admin.cpython-39.pyc ├── apps.cpython-39.pyc ├── models.cpython-39.pyc ├── stockModule.cpython-39.pyc └── views.cpython-39.pyc ├── admin.py ├── apps.py ├── migrations ├── 0001_initial.py ├── __init__.py └── __pycache__ │ ├── 0001_initial.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── models.py ├── stockModule.py ├── templates ├── home.html ├── search.html ├── ticker.html └── trader_leaderboards.html ├── tests.py └── views.py /README.md: -------------------------------------------------------------------------------- 1 | # Django_Trading 2 | Stock Paper Trading website using Django and Bootstrap. The app allows users to create a portfolio of stocks in real time. The starting balance per new user created is $1 million dollars. 3 | 4 | # Overview 5 | Progam languages mostly used: Django, python (for backend framework). Used HTML, Bootstrap for front end framework. To get live stock data I used Finnhub (for API), yfinance, and Plotly/Pandas. 6 | 7 | # How to Use 8 | Once you've made an account by hitting signup on the home page, using Django Trading is simple! Use the portfolio tab to monitor the stocks you've bought and sell any. Use the search tab to find stocks, stock info, and to buy stocks. Click the leaderboard tab to monitor other users, and that's about it. 9 | 10 | # Try this app 11 | I welcome pull requests! Please make sure to download all of the packages in the requirements.txt file. Then run the server and enjoy! 12 | -------------------------------------------------------------------------------- /paper_trading/accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/accounts/__init__.py -------------------------------------------------------------------------------- /paper_trading/accounts/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/accounts/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/accounts/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/accounts/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/accounts/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/accounts/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/accounts/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/accounts/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/accounts/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/accounts/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /paper_trading/accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | name = 'accounts' 6 | -------------------------------------------------------------------------------- /paper_trading/accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /paper_trading/accounts/migrations/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/accounts/migrations/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /paper_trading/accounts/templates/account_settings.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 | 5 |
6 |
7 |
8 |

User Settings

9 |
10 |
11 | 12 |
13 |
14 |

Username: {{user.username}}

15 | Change Password 16 |

User since: {{user.date_joined}}

17 | 18 |
19 |
20 | 21 |
22 |
23 |
24 | {% csrf_token %} 25 |
26 | 27 | 28 |
29 |
30 | 31 | 32 |
33 | 34 |
35 | 36 | 37 |
38 | 39 |
40 | 41 | 42 |
43 | 44 | 45 | 46 | 47 |
48 |
49 |
50 | 51 | 75 | 76 |
77 | 78 | 79 | 80 | {% endblock %} -------------------------------------------------------------------------------- /paper_trading/accounts/templates/change_password.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 | 5 |
6 |
7 |
8 |
9 | {% csrf_token %} 10 | {{ form }} 11 | 12 |
13 |
14 | 15 | 16 |
17 | 18 | {% endblock %} -------------------------------------------------------------------------------- /paper_trading/accounts/templates/portfolio.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 | Demo Trading | Portfolio 5 | 6 | 7 |
8 |
9 |
10 |
{{request.user.username}}
11 |
12 |
13 | 14 |
15 |
16 |

Cash: ${{CurrentTrader.cash}}

17 |
18 |
19 | 20 |
21 |
22 |

AUM: ${{CurrentTrader.AUM}}

23 |
24 |
25 | 26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | {% for position in PositionsArray %} 48 | 49 | 50 | 51 | 52 | 53 | 54 | 67 | 68 | 69 | 70 | 71 | {% endfor %} 72 | 73 |
TickerCountShare PricePosition Value
{{position.ticker}}{{position.count}}${{position.price}}${{position.value}} 55 |
56 | {% csrf_token %} 57 | 59 | 60 | 61 |
62 | 63 | 64 | 65 | 66 |
74 | 75 | 76 | 77 | {% endblock %} -------------------------------------------------------------------------------- /paper_trading/accounts/templates/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 |
12 |

Sign up

13 | 14 |
15 | {% csrf_token %} 16 | 17 |
18 | 19 | 21 | Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. 22 | 23 |
24 | 25 |
26 | 27 | 29 |
30 | 31 |
    32 |
  • Your password can’t be too similar to your other personal information.
  • 33 |
  • Your password must contain at least 8 characters.
  • 34 |
  • Your password can’t be a commonly used password.
  • 35 |
  • Your password can’t be entirely numeric.
  • 36 |
37 |
38 |
39 | 40 |
41 | 42 | 44 |
45 | Enter the same password as before, for verification. 46 |
47 |
48 | 49 | 50 |
51 | 52 |
53 | 54 | 55 |
56 | 57 |
58 | 59 | 60 |
61 | 62 | 63 | 64 | 65 |
66 | 67 | 68 | 69 | 70 | 71 |
72 | 73 | 74 |
75 |
76 | 77 | {% endblock %} 78 | 79 | 80 | 81 | 82 |
Required. 150 characters or fewer. Letters, digits and 84 | @/./+/-/_ only. 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 | 94 | 100 | 101 | 102 | 103 | 104 |
Enter the same password as before, for verification. 106 | -------------------------------------------------------------------------------- /paper_trading/accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /paper_trading/accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.template import RequestContext 3 | 4 | # Create your views here. 5 | from django.contrib.auth import login, authenticate 6 | from django.contrib.auth.forms import UserCreationForm 7 | from django.shortcuts import render, redirect 8 | from trader.models import Trader 9 | from django.contrib.auth.decorators import login_required 10 | import json 11 | from dataclasses import dataclass 12 | from yahoo_fin.stock_info import get_live_price 13 | from django.http import HttpResponse 14 | from trader.stockModule import Stock 15 | from django.http import HttpResponseRedirect 16 | from django.shortcuts import redirect 17 | from django.contrib.auth import logout 18 | from plotly.offline import plot 19 | import plotly.graph_objs as go 20 | from django.contrib.auth.forms import PasswordChangeForm 21 | from django.contrib import messages 22 | from django.contrib.auth import update_session_auth_hash 23 | 24 | 25 | def signup(request): 26 | if request.method == 'POST': 27 | form = UserCreationForm(request.POST) 28 | if form.is_valid(): 29 | print("FSD") 30 | form.save() 31 | username = form.cleaned_data.get('username') 32 | raw_password = form.cleaned_data.get('password1') 33 | user = authenticate(username=username, password=raw_password) 34 | login(request, user) 35 | return redirect('/accounts/login/') 36 | else: 37 | print("ERROR") 38 | messages.error(request, 'Invalid information.') 39 | 40 | else: 41 | form = UserCreationForm() 42 | return render(request, 'signup.html', {'form': form}) 43 | 44 | 45 | @login_required 46 | def portfolio(request): 47 | CurrentTrader = Trader.objects.get(user=request.user) 48 | positionsDict = (json.loads( 49 | str(CurrentTrader.positions).replace("'", '"'))) 50 | CurrentTrader.AUM = round(Stock.getPositionValue( 51 | positionsDict) + float(CurrentTrader.cash), 3) 52 | StockArray = [] 53 | 54 | for i in positionsDict.keys(): 55 | if i == "name": 56 | continue 57 | stockPrice = get_live_price(i) 58 | 59 | positionInfo = { 60 | 'ticker': i, 61 | 'count': positionsDict[i], 62 | 'price': round(stockPrice, 3), 63 | 'value': round(stockPrice * positionsDict[i], 3), 64 | 65 | } 66 | 67 | StockArray.append(positionInfo) 68 | 69 | context = {"User": request.user, 70 | "CurrentTrader": CurrentTrader, 71 | "PositionsArray": StockArray 72 | } 73 | 74 | return render(request, 'portfolio.html', context) 75 | 76 | 77 | @login_required 78 | def logout_user(request): 79 | logout(request) 80 | 81 | 82 | @login_required 83 | def account_settings(request): 84 | 85 | context = {} 86 | return render(request, "account_settings.html", context) 87 | 88 | 89 | @login_required 90 | def change_info(request): 91 | 92 | if request.method == "POST": 93 | currentUser = request.user 94 | currentUser.username = request.POST.get("username") 95 | currentUser.first_name = request.POST.get('first_name') 96 | currentUser.last_name = request.POST.get("last_name") 97 | currentUser.email = request.POST.get("email") 98 | currentUser.save() 99 | return redirect("/accounts/account_settings/") 100 | else: 101 | return HttpResponse("BAD!") 102 | 103 | 104 | @login_required 105 | def change_password(request): 106 | if request.method == 'POST': 107 | form = PasswordChangeForm(request.user, request.POST) 108 | if form.is_valid(): 109 | user = form.save() 110 | update_session_auth_hash(request, user) # Important! 111 | messages.success( 112 | request, 'Your password was successfully updated!') 113 | return redirect('change_password') 114 | else: 115 | messages.error(request, 'Please correct the error below.') 116 | else: 117 | form = PasswordChangeForm(request.user) 118 | return render(request, 'change_password.html', { 119 | 'form': form 120 | }) 121 | -------------------------------------------------------------------------------- /paper_trading/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'paper_trading.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /paper_trading/paper_trading/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/paper_trading/__init__.py -------------------------------------------------------------------------------- /paper_trading/paper_trading/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/paper_trading/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/paper_trading/__pycache__/settings.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/paper_trading/__pycache__/settings.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/paper_trading/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/paper_trading/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/paper_trading/__pycache__/wsgi.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/paper_trading/__pycache__/wsgi.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/paper_trading/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for paper_trading project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'paper_trading.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /paper_trading/paper_trading/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for paper_trading project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.1.3. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.1/ref/settings/ 11 | """ 12 | 13 | import os 14 | from pathlib import Path 15 | 16 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 17 | BASE_DIR = Path(__file__).resolve().parent.parent 18 | 19 | 20 | # Quick-start development settings - unsuitable for production 21 | # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ 22 | 23 | # SECURITY WARNING: keep the secret key used in production secret! 24 | SECRET_KEY = '($+ft1e!%t9b_+m%4fruc*zn7dqew9nrb7d07)bb&q2flqj9%8' 25 | 26 | # SECURITY WARNING: don't run with debug turned on in production! 27 | DEBUG = True 28 | 29 | ALLOWED_HOSTS = [] 30 | 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | 'trader.apps.TraderConfig', 36 | 'accounts.apps.AccountsConfig', 37 | 'django.contrib.admin', 38 | 'django.contrib.auth', 39 | 'django.contrib.contenttypes', 40 | 'django.contrib.sessions', 41 | 'django.contrib.messages', 42 | 'django.contrib.staticfiles', 43 | ] 44 | 45 | MIDDLEWARE = [ 46 | 'django.middleware.security.SecurityMiddleware', 47 | 'django.contrib.sessions.middleware.SessionMiddleware', 48 | 'django.middleware.common.CommonMiddleware', 49 | 'django.middleware.csrf.CsrfViewMiddleware', 50 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 51 | 'django.contrib.messages.middleware.MessageMiddleware', 52 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 53 | ] 54 | 55 | ROOT_URLCONF = 'paper_trading.urls' 56 | 57 | TEMPLATES = [ 58 | { 59 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 60 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], 61 | 'APP_DIRS': True, 62 | 'OPTIONS': { 63 | 'context_processors': [ 64 | 'django.template.context_processors.debug', 65 | 'django.template.context_processors.request', 66 | 'django.contrib.auth.context_processors.auth', 67 | 'django.contrib.messages.context_processors.messages', 68 | ], 69 | }, 70 | }, 71 | ] 72 | 73 | WSGI_APPLICATION = 'paper_trading.wsgi.application' 74 | 75 | 76 | # Database 77 | # https://docs.djangoproject.com/en/3.1/ref/settings/#databases 78 | 79 | DATABASES = { 80 | 'default': { 81 | #'ENGINE': 'django.db.backends.sqlite3', 82 | #'NAME': BASE_DIR / 'db.sqlite3', 83 | 'ENGINE': 'django.db.backends.mysql', 84 | 'NAME': 'stocks101', 85 | 'HOST': '127.0.0.1', 86 | 'USER': 'root', 87 | 'PASSWORD': 'root', 88 | 'PORT': '3306' 89 | } 90 | } 91 | 92 | 93 | # Password validation 94 | # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators 95 | 96 | AUTH_PASSWORD_VALIDATORS = [ 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 99 | }, 100 | { 101 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 102 | }, 103 | { 104 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 105 | }, 106 | { 107 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 108 | }, 109 | ] 110 | 111 | 112 | # Internationalization 113 | # https://docs.djangoproject.com/en/3.1/topics/i18n/ 114 | 115 | LANGUAGE_CODE = 'en-us' 116 | 117 | TIME_ZONE = 'UTC' 118 | 119 | USE_I18N = True 120 | 121 | USE_L10N = True 122 | 123 | USE_TZ = True 124 | 125 | # Static files (CSS, JavaScript, Images) 126 | # https://docs.djangoproject.com/en/3.0/howto/static-files/ 127 | 128 | LOGIN_REDIRECT_URL = '/accounts/portfolio/' 129 | LOGOUT_REDIRECT_URL = '/home/' 130 | 131 | 132 | PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) 133 | 134 | # Static files (CSS, JavaScript, Images) 135 | # https://docs.djangoproject.com/en/1.9/howto/static-files/ 136 | STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles') 137 | STATIC_URL = '/static/' 138 | 139 | # Extra places for collectstatic to find static files. 140 | STATICFILES_DIRS = ( 141 | os.path.join(PROJECT_ROOT, 'static'), 142 | ) 143 | 144 | # Static files (CSS, JavaScript, Images) 145 | # https://docs.djangoproject.com/en/3.1/howto/static-files/ 146 | 147 | STATIC_URL = '/static/' 148 | -------------------------------------------------------------------------------- /paper_trading/paper_trading/urls.py: -------------------------------------------------------------------------------- 1 | """paper_trading URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.1/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | 17 | from django.conf.urls import url, include 18 | from django.shortcuts import redirect 19 | 20 | from accounts import views as core_views 21 | from django.contrib import admin 22 | from django.urls import path 23 | from trader.views import leaderboard_list_view, index, search, buy, sell, home_view 24 | from accounts.views import portfolio, signup, logout_user, change_password, account_settings, change_info 25 | urlpatterns = [ 26 | path('admin/', admin.site.urls), 27 | path('leaderboard/', leaderboard_list_view), 28 | url(r'^signup/$', core_views.signup, name='signup'), 29 | path('accounts/', include('django.contrib.auth.urls')), 30 | path('accounts/portfolio/', portfolio), 31 | path('index/', index), 32 | path('search/', search), 33 | path('accounts/buy/', buy), 34 | path('accounts/sell/', sell), 35 | path('accounts/signup/', signup), 36 | path('accounts/logout/', logout_user), 37 | path('accounts/account_settings/', account_settings), 38 | path('accounts/change_password/', change_password), 39 | path('accounts/change_info/', change_info), 40 | path('home/', home_view), 41 | path("", home_view) 42 | ] 43 | -------------------------------------------------------------------------------- /paper_trading/paper_trading/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for paper_trading project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'paper_trading.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /paper_trading/requirements.txt: -------------------------------------------------------------------------------- 1 | amqp==1.4.9 2 | anyjson==0.3.3 3 | appdirs==1.4.4 4 | asgiref==3.2.10 5 | astroid==2.3.3 6 | beautifulsoup4==4.9.1 7 | billiard==3.3.0.23 8 | bs4==0.0.1 9 | certifi==2020.6.20 10 | chardet==3.0.4 11 | colorama==0.4.3 12 | cssselect==1.1.0 13 | dataclasses==0.6 14 | decorator==4.4.2 15 | distlib==0.3.0 16 | dj-database-url==0.5.0 17 | Django==3.0.7 18 | django-heroku==0.3.1 19 | djangorestframework==3.11.0 20 | fake-useragent==0.1.11 21 | filelock==3.0.12 22 | gunicorn==20.0.4 23 | idna==2.9 24 | importlib-metadata==1.6.0 25 | isort==4.3.21 26 | jsonfield==3.1.0 27 | kombu==3.0.37 28 | lazy-object-proxy==1.4.3 29 | lxml==4.5.1 30 | mccabe==0.6.1 31 | multitasking==0.0.9 32 | networkx==2.4 33 | numpy==1.18.3 34 | pandas==1.0.3 35 | parse==1.15.0 36 | plotly==4.8.2 37 | psycopg2==2.8.5 38 | pyee==7.0.2 39 | pylint==2.4.4 40 | pyppeteer==0.2.2 41 | pyquery==1.4.1 42 | python-dateutil==2.8.1 43 | python-decouple==3.3 44 | python-dotenv==0.14.0 45 | pytz==2019.3 46 | requests==2.24.0 47 | requests-html==0.10.0 48 | retrying==1.3.3 49 | six==1.14.0 50 | soupsieve==2.0.1 51 | sqlparse==0.3.1 52 | tqdm==4.46.1 53 | typed-ast==1.4.1 54 | urllib3==1.25.9 55 | virtualenv==20.0.21 56 | w3lib==1.22.0 57 | websockets==8.1 58 | whitenoise==5.1.0 59 | wrapt==1.11.2 60 | XlsxWriter==1.3.3 61 | yahoo-fin==0.8.5 62 | yfinance==0.1.54 63 | zipp==3.1.0 64 | -------------------------------------------------------------------------------- /paper_trading/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% if messages %} 17 | 24 | {% endif %} 25 | 66 | 98 | 99 | 102 | 105 | 108 | 109 | {% block content %}{% endblock content %} 110 | 111 | 112 | -------------------------------------------------------------------------------- /paper_trading/templates/foreign_base.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 39 | 40 | 41 | 44 | 47 | 50 | 51 | {% block content %}{% endblock content %} 52 | 53 | 54 | -------------------------------------------------------------------------------- /paper_trading/templates/registration/login.html: -------------------------------------------------------------------------------- 1 | {% extends "foreign_base.html" %} 2 | {% block content %} 3 | 4 | 5 |
6 |
7 |
8 |

Login

9 |
10 | {% csrf_token %} 11 | 12 |

13 | 14 | 16 |

17 | 18 |

19 | 20 | 22 |

23 | 24 |
25 | 26 |
27 |
28 |
29 | 30 | {% endblock %} -------------------------------------------------------------------------------- /paper_trading/trader/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/trader/__init__.py -------------------------------------------------------------------------------- /paper_trading/trader/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/trader/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/trader/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/trader/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/trader/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/trader/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/trader/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/trader/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/trader/__pycache__/stockModule.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/trader/__pycache__/stockModule.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/trader/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/trader/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/trader/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Trader 3 | # Register your models here. 4 | 5 | admin.site.register(Trader) 6 | -------------------------------------------------------------------------------- /paper_trading/trader/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class TraderConfig(AppConfig): 5 | name = 'trader' 6 | -------------------------------------------------------------------------------- /paper_trading/trader/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.3 on 2020-12-03 01:40 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | import jsonfield.fields 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Trader', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('positions', jsonfield.fields.JSONField(default={'name': 'positions'})), 23 | ('pastReturns', jsonfield.fields.JSONField(default={'name': 'pastReturns'})), 24 | ('cash', models.IntegerField(default=1000000)), 25 | ('AUM', models.IntegerField(default=1000000)), 26 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 27 | ], 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /paper_trading/trader/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/trader/migrations/__init__.py -------------------------------------------------------------------------------- /paper_trading/trader/migrations/__pycache__/0001_initial.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/trader/migrations/__pycache__/0001_initial.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/trader/migrations/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trahyns/Django_Trading/9eee9a56918228372050dce69b868f99ed072474/paper_trading/trader/migrations/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /paper_trading/trader/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | from django.db.models.signals import post_save 4 | from django.dispatch import receiver 5 | from jsonfield import JSONField 6 | 7 | # Create your models here. 8 | 9 | class Trader(models.Model): 10 | user = models.OneToOneField(User, on_delete=models.CASCADE) 11 | positions = JSONField(default={'name': "positions"}) 12 | 13 | pastReturns = JSONField(default={'name': "pastReturns"}) 14 | 15 | cash = models.IntegerField(default=1_000_000) 16 | AUM = models.IntegerField(default=1_000_000) 17 | 18 | 19 | @receiver(post_save, sender=User) 20 | def create_user_profile(sender, instance, created, **kwargs): 21 | if created: 22 | Trader.objects.create(user=instance) 23 | 24 | 25 | @receiver(post_save, sender=User) 26 | def save_user_profile(sender, instance, **kwargs): 27 | instance.trader.save() 28 | -------------------------------------------------------------------------------- /paper_trading/trader/stockModule.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import xlsxwriter 4 | import pandas as pd 5 | import os 6 | import yfinance as yf 7 | import yahoo_fin.stock_info 8 | from plotly.offline import plot 9 | import plotly.graph_objs as go 10 | import plotly.express as px 11 | 12 | 13 | class Stock: 14 | API_KEY = "bv4403v48v6tcp17fv10" 15 | 16 | def __init__(self, ticker): 17 | self.ticker = ticker 18 | self.tickerName = ticker.info["symbol"] 19 | 20 | def __str__(self): 21 | return self.ticker.info["shortName"] 22 | 23 | def getAnnualFinancialsReported(self): 24 | r = requests.get( 25 | 'https://finnhub.io/api/v1/stock/financials-reported?symbol='+tickerName+'&token='+API_KEY) 26 | return r.json() 27 | 28 | def getCompanyProfile(self): 29 | r = requests.get( 30 | 'https://finnhub.io/api/v1/stock/profile2?symbol=AAPL&token=bv4403v48v6tcp17fv10') 31 | return r.json() 32 | 33 | def getPlotlyPriceHistory(self, tickerName, price, period="1d", interval="5m"): 34 | 35 | priceDF = self.ticker.history(period=period, interval=interval) 36 | priceDF["DatetimeCol"] = priceDF.index 37 | #fig = go.Figure([go.Line(x=priceDF["DatetimeCol"], y=priceDF['Close'])]) 38 | 39 | data = go.Line(x=priceDF["DatetimeCol"], y=priceDF['Close']) 40 | layout = go.Layout( 41 | title=period, 42 | 43 | titlefont=dict( 44 | 45 | #family="Courier New, monospace", 46 | size=30, 47 | color="#7f7f7f" 48 | ), 49 | margin=dict(l=0, r=0, t=0.1, b=0), 50 | plot_bgcolor="#FFFFFF" 51 | 52 | ) 53 | 54 | fig = go.Figure( 55 | data=data, 56 | layout=layout 57 | ) 58 | fig.update_layout( 59 | font_family="Arial", 60 | font_color="blue", 61 | title={ 62 | 'text': period, 63 | "y": 1, 64 | "x": 0.5}, 65 | 66 | 67 | ) 68 | ''' 69 | fig.update_layout( 70 | title=str(tickerName) + "
$" + str(price) +"

", 71 | title_x=0.04, 72 | title_y=0.93, 73 | titlefont=dict( 74 | #family="Courier New, monospace", 75 | size=30, 76 | color="#7f7f7f" 77 | ), 78 | margin=dict(l=0, r=0, t=00, b=0), 79 | ) 80 | ''' 81 | plt_div = plot(fig, output_type='div') 82 | 83 | return plt_div 84 | 85 | @classmethod 86 | def getPositionValue(cls, positionsJSON): 87 | value = 0 88 | for positionKey in positionsJSON.keys(): 89 | if (positionKey == "name"): 90 | continue 91 | value += yahoo_fin.stock_info.get_live_price( 92 | positionKey) * positionsJSON[positionKey] 93 | return value 94 | 95 | def getStockSummary(self): 96 | 97 | stockInfo = self.ticker.info 98 | summaryKeys = set(["previousClose", "regularMarketOpen", "twoHundredDayAverage", 99 | "fiftyDayAverage", "open", "beta", "currency", "volume", 100 | "trailingPE", "forwardPE", "exchange", "shortName", 101 | "profitMargins", "52WeekChange", "shortRatio", "volume", 102 | "fiftyTwoWeekHigh", "enterpriseToEbitda", "marketCap", "volume", 103 | "city", "industry", "currency"]) 104 | newDict = {} 105 | for i in stockInfo.keys(): 106 | 107 | if (i in summaryKeys): 108 | newDict[i] = stockInfo[i] 109 | newDict["longBusinessSummary"] = self.ticker.info["longBusinessSummary"] 110 | return newDict 111 | -------------------------------------------------------------------------------- /paper_trading/trader/templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends "foreign_base.html" %} 2 | 3 | 4 | {% block content %} 5 |
6 |
7 |
8 |

Welcome to Demo Trading!

9 |
10 |

11 | Welcome future investor! This is a free, online paper trading platorm. Start off with 1 million dollars and 12 | be the best investor! Sign up to get started! 13 |

14 |

15 | 17 |

via GIPHY

18 |

19 |
20 |
21 | 22 |
23 | 24 | 25 | 26 | {% endblock %} -------------------------------------------------------------------------------- /paper_trading/trader/templates/search.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 | Demo Trading | {{TickerName}} 5 | 6 | 7 | 8 |
9 |
10 |
11 |

{{Summary.shortName}} ({{TickerName}})

12 |

${{Price}}

13 |
14 | 15 |
16 |
17 | {% csrf_token %} 18 | 19 | 20 | 21 |
22 |
23 | 24 | 25 |
26 | 27 |
28 | 29 |
30 | {{StockPlot|safe }} 31 |
32 | 33 |
34 | 35 |
36 |
37 | 107 |
108 |
109 | 110 |
111 | 112 | 113 | 114 | 115 | 116 |
117 |
118 |

Business Summary

119 |
120 |
121 | 122 |
123 | 124 |
125 |
126 |

{{Summary.longBusinessSummary}}

127 |
128 |
129 | 130 |
131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 |
IndustryExchangeLocationFounded
{{Summary.industry}}{{Profile.exchange}}{{Summary.city}}{{Summary.currency}}
Previous CloseMarket OpenMarket CapVolume
${{Summary.previousClose}}${{Summary.regularMarketOpen}}${{Summary.marketCap}}{{Summary.volume}}
Trailing PEForward PEBetaShort Ratio
{{Summary.trailingPE}}{{Summary.forwardPE}}{{Summary.beta}}{{Summary.shortRatio}}
177 |
178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | {% endblock %} -------------------------------------------------------------------------------- /paper_trading/trader/templates/ticker.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 |
4 | {% csrf_token %} 5 | 6 | 7 |
8 | 9 | {% endblock %} -------------------------------------------------------------------------------- /paper_trading/trader/templates/trader_leaderboards.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 | Demo Trading | Leaderboard 5 | 6 | 7 |


8 |
9 |
10 | 11 |
12 |

Leaderboard

13 |
14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {% for trader in trader_objects %} 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | {% endfor %} 38 | 39 |
PositionUsernameAUM
{{Summary.marketCap}}{{trader.user.username}}${{trader.AUM}}
40 | 41 | 42 | 43 | 57 | 58 | 59 | {% endblock %} -------------------------------------------------------------------------------- /paper_trading/trader/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /paper_trading/trader/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.shortcuts import render 3 | from .models import Trader 4 | import json 5 | from .stockModule import Stock 6 | from django.contrib.auth.decorators import login_required 7 | from yahoo_fin.stock_info import get_live_price, get_data 8 | import yfinance as yf 9 | from django.http import HttpResponse 10 | from plotly.offline import plot 11 | import plotly.graph_objs as go 12 | from django.http import HttpResponseRedirect 13 | from accounts.views import portfolio 14 | from django.shortcuts import redirect 15 | from django.contrib import messages 16 | 17 | # Create your views here. 18 | 19 | 20 | def home_view(request): 21 | if request.user.is_authenticated: 22 | return redirect('/accounts/portfolio/') 23 | return render(request, "home.html") 24 | 25 | 26 | @login_required 27 | def leaderboard_list_view(request): 28 | trader_objects = Trader.objects.all() 29 | 30 | for trader in trader_objects: 31 | positionsDict = (json.loads(str(trader.positions).replace("'", '"'))) 32 | trader.AUM = Stock.getPositionValue(positionsDict) + float(trader.cash) 33 | trader.save() 34 | 35 | trader_objects = Trader.objects.order_by('-AUM') 36 | 37 | context = { 38 | "trader_objects": trader_objects, 39 | "ranks": range(0, len(trader_objects)) 40 | } 41 | 42 | return render(request, "trader_leaderboards.html", context) 43 | 44 | 45 | @login_required 46 | def sell(request): 47 | CurrentTrader = Trader.objects.get(user=request.user) 48 | 49 | positionsDict = (json.loads( 50 | str(CurrentTrader.positions).replace("'", '"'))) 51 | CurrentTrader.AUM = Stock.getPositionValue( 52 | positionsDict) + float(CurrentTrader.cash) 53 | if request.method == "POST": 54 | ShareCount = int(request.POST.get('ShareCount', None)) 55 | TickerName = str(request.POST.get('TickerName')) 56 | print(request.POST) 57 | Price = get_live_price(TickerName) 58 | if (ShareCount > positionsDict[TickerName]): 59 | messages.add_message(request, messages.INFO, 60 | 'Too many stocks being sold') 61 | return HttpResponseRedirect("/accounts/portfolio/") 62 | 63 | CurrentTrader.cash = CurrentTrader.cash + (ShareCount * Price) 64 | if (TickerName in positionsDict.keys()): 65 | positionsDict[TickerName] = positionsDict[TickerName] - ShareCount 66 | if (positionsDict[TickerName] == 0): 67 | del positionsDict[TickerName] 68 | CurrentTrader.positions = positionsDict 69 | 70 | else: 71 | messages.add_message(request, messages.INFO, 72 | 'Do not own this stock') 73 | 74 | return HttpResponse("/accounts/portfolio") 75 | 76 | CurrentTrader.AUM = Stock.getPositionValue( 77 | positionsDict) + float(CurrentTrader.cash) 78 | CurrentTrader.save() 79 | return HttpResponseRedirect('/accounts/portfolio/') 80 | else: 81 | return HttpResponse("Purchase failed") 82 | 83 | 84 | @login_required 85 | def buy(request): 86 | CurrentTrader = Trader.objects.get(user=request.user) 87 | 88 | positionsDict = (json.loads( 89 | str(CurrentTrader.positions).replace("'", '"'))) 90 | CurrentTrader.AUM = Stock.getPositionValue( 91 | positionsDict) + float(CurrentTrader.cash) 92 | if request.method == "POST": 93 | ShareCount = int(request.POST.get('ShareCount', None)) 94 | TickerName = str(request.POST.get('TickerName')).upper() 95 | Price = get_live_price(TickerName) 96 | if (CurrentTrader.cash < ShareCount * Price): 97 | return HttpResponse("Not enough cash") 98 | 99 | CurrentTrader.cash = CurrentTrader.cash - (ShareCount * Price) 100 | if (TickerName in positionsDict.keys()): 101 | positionsDict[TickerName] = positionsDict[TickerName] + ShareCount 102 | CurrentTrader.positions = positionsDict 103 | else: 104 | positionsDict[TickerName] = ShareCount 105 | CurrentTrader.positions = positionsDict 106 | 107 | CurrentTrader.AUM = Stock.getPositionValue( 108 | positionsDict) + float(CurrentTrader.cash) 109 | 110 | CurrentTrader.save() 111 | return HttpResponseRedirect('/accounts/portfolio/') 112 | else: 113 | return HttpResponse("Purchase failed") 114 | 115 | 116 | @login_required 117 | def index(request): 118 | return render(request, 'ticker.html') 119 | 120 | 121 | @login_required 122 | def search(request): 123 | if request.method == 'POST': 124 | 125 | try: 126 | tickerName = request.POST.get('ticker', None).upper() 127 | graphTime = request.POST.get("graphTime", None) 128 | 129 | graphConfigurations = [ 130 | ("1d", "1m"), 131 | ("5d", "15m"), 132 | ("1mo", "1h"), 133 | ("3mo", "1d"), 134 | ("1y", "1d"), 135 | ("5y", "1wk"), 136 | ("max", "1mo"), 137 | ] 138 | 139 | get_data(tickerName) 140 | stock = Stock(yf.Ticker(tickerName)) 141 | price = round(get_live_price(tickerName), 3) 142 | 143 | Summary = stock.getStockSummary() 144 | titleName = Summary["shortName"] + "(" + tickerName + ")" 145 | 146 | if graphTime is not None: 147 | graphTime = int(graphTime) 148 | plt = stock.getPlotlyPriceHistory(titleName, price, 149 | period=graphConfigurations[graphTime][0], interval=graphConfigurations[graphTime][1]) 150 | else: 151 | plt = stock.getPlotlyPriceHistory( 152 | titleName, price, period="1d", interval="1m") 153 | 154 | #user = Person.objects.get(name = search_id) 155 | #do something with user 156 | #html = ("

%s

", user) 157 | context = { 158 | "TickerName": tickerName, 159 | "Price": price, 160 | "Summary": Summary, 161 | "Profile": stock.getCompanyProfile, 162 | "StockPlot": plt 163 | 164 | } 165 | return render(request, "search.html", context) 166 | except AssertionError: 167 | return HttpResponse("no such stock") 168 | else: 169 | return render(request, 'form.html') 170 | --------------------------------------------------------------------------------