Merge pull request #41 from WebEngineering2/symbol_price

Save symbol price in database
This commit is contained in:
Florian Kaiser 2022-04-05 15:32:55 +02:00 committed by GitHub
commit 772a4d2c60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 165 additions and 12 deletions

View File

@ -16,3 +16,6 @@ BOT_PASSWORD=
ADMIN_EMAIL=
ADMIN_USERNAME=
ADMIN_PASSWORD=
# API URL (used for load_share_price.py and generate_sample_transactions.py)
API_URL=

View File

@ -7,6 +7,7 @@ from flask_cors import CORS
from app.blueprints.keyword import keyword_blueprint
from app.blueprints.portfolio import portfolio_blueprint
from app.blueprints.shares import shares_blueprint
from app.blueprints.share_price import share_price_blueprint
from app.blueprints.transactions import transaction_blueprint
from app.blueprints.telegram import telegram_blueprint
from app.blueprints.user import users_blueprint
@ -28,6 +29,7 @@ def create_app(config_filename=None):
# api blueprints
application.register_blueprint(keyword_blueprint)
application.register_blueprint(shares_blueprint)
application.register_blueprint(share_price_blueprint)
application.register_blueprint(transaction_blueprint)
application.register_blueprint(portfolio_blueprint)
application.register_blueprint(users_blueprint)

View File

@ -2,10 +2,11 @@ import os
from apiflask import APIBlueprint
from app.schema import PortfolioResponseSchema
from app.models import SharePrice
from app.auth import auth
from app.db import database as db
from app.helper_functions import make_response, get_email_or_abort_401
from app.auth import auth
from app.schema import PortfolioResponseSchema
portfolio_blueprint = APIBlueprint('portfolio', __name__, url_prefix='/api')
__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
@ -23,11 +24,18 @@ def get_portfolio():
if transactions is not None:
for row in transactions:
return_portfolio.append({
data = {
"symbol": row[0],
"count": row[1],
# "price": row[2],
"last_transaction": row[3]
})
# "calculated_price": row[2],
"last_transaction": row[3],
'current_price': 0
}
query_share_price = db.session.query(SharePrice).filter_by(symbol=row[0]).first()
if query_share_price is not None:
data['current_price'] = query_share_price.as_dict()['price']
return_portfolio.append(data)
return make_response(return_portfolio, 200, "Successfully loaded symbols")

View File

@ -0,0 +1,88 @@
import datetime
import os
from apiflask import APIBlueprint, abort
from app.models import SharePrice
from app.db import database as db
from app.helper_functions import make_response
from app.auth import auth
from app.schema import SymbolPriceSchema
share_price_blueprint = APIBlueprint('share_price', __name__, url_prefix='/api')
__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
@share_price_blueprint.route('/symbols', methods=['GET'])
@share_price_blueprint.output({}, 200)
@share_price_blueprint.auth_required(auth)
@share_price_blueprint.doc(summary="Returns all transaction symbols", description="Returns all transaction symbols for all users")
def get_transaction_symbols():
symbols = db.session.execute("SELECT symbol FROM `transactions` GROUP BY symbol;").all()
return_symbols = []
for s in symbols:
return_symbols.append(s[0])
return make_response(return_symbols, 200, "Successfully loaded symbols")
@share_price_blueprint.route('/symbol', methods=['POST'])
@share_price_blueprint.output({}, 200)
@share_price_blueprint.input(schema=SymbolPriceSchema)
@share_price_blueprint.auth_required(auth)
@share_price_blueprint.doc(summary="Returns all transaction symbols", description="Returns all transaction symbols for all users")
def add_symbol_price(data):
if not check_if_symbol_data_exists(data):
abort(400, message="Symbol missing")
if not check_if_price_data_exists(data):
abort(400, message="Price missing")
if not check_if_time_data_exists(data):
abort(400, message="Time missing")
symbol = data['symbol']
price = data['price']
time = data['time']
share_price = SharePrice(
symbol=symbol,
price=price,
date=datetime.datetime.strptime(time, '%Y-%m-%dT%H:%M:%S.%fZ'),
)
db.session.add(share_price)
db.session.commit()
return make_response(share_price.as_dict(), 200, "Successfully added price")
def check_if_symbol_data_exists(data):
if 'symbol' not in data:
return False
if data['symbol'] == "" or data['symbol'] is None:
return False
return True
def check_if_price_data_exists(data):
if 'price' not in data:
return False
if data['price'] == "" or data['price'] is None:
return False
return True
def check_if_time_data_exists(data):
if 'time' not in data:
return False
if data['time'] == "" or data['time'] is None:
return False
return True

View File

@ -1,13 +1,13 @@
import os
import datetime
import os
from apiflask import abort, APIBlueprint
from app.auth import auth
from app.db import database as db
from app.helper_functions import make_response, get_email_or_abort_401
from app.models import Transaction
from app.schema import TransactionSchema, TransactionResponseSchema
from app.auth import auth
transaction_blueprint = APIBlueprint('transaction', __name__, url_prefix='/api')
__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))

View File

@ -51,3 +51,14 @@ class Share(db.Model):
def as_dict(self):
return {c.name: getattr(self, c.name) for c in self.__table__.columns}
class SharePrice(db.Model):
__tablename__ = 'share_price'
id = db.Column('id', db.Integer(), nullable=False, unique=True, primary_key=True)
symbol = db.Column('symbol', db.String(255))
price = db.Column('price', db.Float())
date = db.Column('date', db.DateTime())
def as_dict(self):
return {c.name: getattr(self, c.name) for c in self.__table__.columns}

View File

@ -75,6 +75,12 @@ class TransactionSchema(Schema):
price = Float()
class SymbolPriceSchema(Schema):
symbol = String()
time = String(validate=validate.Regexp(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z"))
price = Float()
class TelegramIdSchema(Schema):
telegram_user_id = String()

View File

@ -1,9 +1,9 @@
import os
import random
import faker
import requests
url = 'http://127.0.0.1:5000/api'
username = ''
password = ''
@ -12,7 +12,7 @@ shares = ["TWTR", "GOOG", "AAPL", "MSFT", "AMZN", "FB", "NFLX", "TSLA", "BABA",
fake = faker.Faker()
token = requests.post(url + '/user/login', json={"email": username, "password": password}).json()['data']['token']
token = requests.post(os.getenv("API_URL") + '/user/login', json={"email": username, "password": password}).json()['data']['token']
for i in range(1, 1000):
payload = {
@ -22,4 +22,4 @@ for i in range(1, 1000):
"time": fake.date_time().isoformat() + ".000Z"
}
response = requests.post(url + '/transaction', json=payload, headers={'Authorization': 'Bearer ' + token})
response = requests.post(os.getenv("API_URL") + '/transaction', json=payload, headers={'Authorization': 'Bearer ' + token})

33
api/load_share_price.py Normal file
View File

@ -0,0 +1,33 @@
import datetime
import os
import threading
import requests
import yfinance
def thread_function(s):
my_share_info = yfinance.Ticker(s)
my_share_data = my_share_info.info
if my_share_data['regularMarketPrice'] is not None:
payload = {
"symbol": s,
"price": float(my_share_data['regularMarketPrice']),
"time": datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.000Z")
}
requests.post(os.getenv("API_URL") + '/symbol', json=payload, headers={'Authorization': 'Bearer ' + token})
username = os.getenv('ADMIN_EMAIL')
password = os.getenv('ADMIN_PASSWORD')
token = requests.post(os.getenv("API_URL") + '/user/login', json={"email": username, "password": password}).json()['data']['token']
response = requests.get(os.getenv("API_URL") + '/symbols', headers={'Authorization': 'Bearer ' + token}).json()['data']
for symbol in response:
x = threading.Thread(target=thread_function, args=(symbol,))
x.start()

View File

@ -11,4 +11,6 @@ bcrypt==3.2.0
pytest~=7.1.1
pytest-cov
marshmallow~=3.15.0
faker~=4.0.0
faker~=4.0.0
yfinance~=0.1.6
requests~=2.22.0