· 4 years ago · Aug 27, 2021, 10:08 PM
1#region Imports
2import pandas as pd
3import datetime as dt
4import pandas_datareader.data as web
5from sqlalchemy.sql.elements import Null
6#from requests.sessions import session
7import yfinance as yf
8import flask
9from flask import request, jsonify, session, Response
10from flask import (Blueprint, send_from_directory, abort, request,
11 render_template, current_app, render_template, redirect,
12 url_for, current_app)
13from flask_cors import CORS, cross_origin
14import json
15from datetime import datetime, timezone, timedelta
16from marshmallow import Schema, fields
17from typing import List
18import sys
19from algorithms.threeBar import check3bar
20from algorithms.twoMinOpening import twoMinOpening
21from algorithms.breakouts import breakouts
22from algorithms.shadow import shadow
23from mytypes.candle import Candle
24from mytypes.TCResponce import TCResponce
25from flask_login import LoginManager, login_required, login_user, logout_user, current_user
26from mytypes.models import User, UserSetting
27from mytypes.LoginForm import LoginForm
28
29import sqlalchemy
30from sqlalchemy import create_engine
31from sqlalchemy.orm import declarative_base
32from sqlalchemy.sql.expression import false, null, true
33from sqlalchemy.sql.sqltypes import Boolean, DateTime, Float
34from sqlalchemy.orm import sessionmaker
35
36import hashlib
37import os
38import uuid
39from sendgrid import SendGridAPIClient
40from sendgrid.helpers.mail import Mail, Content
41import bs4 as bs
42import requests
43#endregion
44
45#region Classes
46class ObjectSchema(Schema):
47 city = fields.Str()
48 name = fields.Str()
49#endregion
50
51#region functions
52def sendEmail(email, message1):
53 try:
54 print("Email: ", email)
55 print("Message ", message1)
56 message = Mail(
57 from_email='info@stockwolftrading.com',
58 to_emails=email,
59 subject='Please validate your StockWolf account',
60 html_content=Content("text/plain", message1))
61 # html_content='<strong>and easy to do anywhere, even with Python</strong>')
62 sg = SendGridAPIClient(
63 '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')
64 response = sg.send(message)
65 print(response.status_code)
66 print(response.body)
67 print(response.headers)
68 except Exception as e:
69 #exc_tb = sys.exc_info()
70 # print(exc_tb.tb_lineno)
71 print(e.message)
72 return 0
73#endregion
74
75#region starter code
76
77# configs
78app = flask.Flask(__name__)
79app.config["SESSION_PERMANENT"] = True
80app.config["DEBUG"] = True
81app.secret_key = 'super secret key'
82app.config['SESSION_TYPE'] = 'filesystem'
83cache = {'candle': 0, 'open': 0, 'close': 0, 'high': 0, 'low': sys.maxsize, 'interval': '1m', 'ticker': ''}
84cors = CORS(app)
85
86# login manager
87login_manager = LoginManager()
88login_manager.init_app(app)
89
90# db connection
91engine = create_engine(
92 'mssql+pyodbc://DESKTOP-MI0ANF3\\SQLEXPRESS/StockWolfTradingDB?driver=SQL+Server+Native+Client+11.0')
93Session = sessionmaker(bind=engine)
94session = Session()
95#endregion
96
97#region routes
98@login_manager.user_loader
99def user_loader(user_id):
100 print("User id: ", user_id)
101 query = session.query(User).filter(User.Email == user_id)
102 user = query.first()
103 return user
104
105@app.route('/updatepass', methods=['POST'])
106def updatepass():
107 try:
108 content = request.json
109 #print('Post content: ', content)
110 query1 = session.query(User).filter(User.Email == content['email'])
111 user1 = query1.first()
112 if user1:
113 salt_from_storage = user1.Password[:32] # 32 is the length of the salt
114 pass_from_storage = user1.Password[32:]
115 pass_calc = hashlib.pbkdf2_hmac('sha256', content['oldpass'].encode('utf-8'), salt_from_storage, 100000)
116 if pass_calc != pass_from_storage:
117 return jsonify({"response": -1})
118
119 salt = os.urandom(32)
120 key = hashlib.pbkdf2_hmac('sha256', content['password'].encode('utf-8'), salt, 100000)
121 #print('salt: ', salt)
122 #print('key: ', key)
123 storage = salt + key
124 user1.Password = storage
125 session.add(user1)
126 session.commit()
127 print('User id: ', user1.UserId)
128 return jsonify({"response": 0})
129 return jsonify({"response": -2})
130 # (RuntimeError, TypeError, NameError, ValueError):
131 except Exception as inst:
132 exc_type, exc_obj, exc_tb = sys.exc_info()
133 print(type(inst))
134 print(inst.args)
135 print(inst)
136 print(exc_tb.tb_lineno)
137 return jsonify({"response": -3})
138
139
140@app.route('/updateprofile', methods=['POST'])
141def updateprofile():
142 try:
143 content = request.json
144 print('Post content: ', content)
145 query1 = session.query(User).filter(User.Email == content['email'])
146 user1 = query1.first()
147 if user1:
148 user1.FirstName = content['firstname']
149 user1.LastName = content['lastname']
150 session.add(user1)
151 session.commit()
152 print('User id: ', user1.UserId)
153 return jsonify({"firstname": user1.FirstName, "lastname": user1.LastName})
154 # (RuntimeError, TypeError, NameError, ValueError):
155 except Exception as inst:
156 exc_type, exc_obj, exc_tb = sys.exc_info()
157 print(type(inst))
158 print(inst.args)
159 print(inst)
160 print(exc_tb.tb_lineno)
161 return jsonify({"firstname": -1})
162
163
164@app.route('/loadprofile', methods=['POST'])
165def loadprofile():
166 try:
167 content = request.json
168 print('Post content: ', content)
169 query1 = session.query(User).filter(User.Email == content['email'])
170 user1 = query1.first()
171 if user1:
172 print('User id: ', user1.UserId)
173 return jsonify({"firstname": user1.FirstName, "lastname": user1.LastName})
174 # (RuntimeError, TypeError, NameError, ValueError):
175 except Exception as inst:
176 exc_type, exc_obj, exc_tb = sys.exc_info()
177 print(type(inst))
178 print(inst.args)
179 print(inst)
180 print(exc_tb.tb_lineno)
181 return jsonify({"firstname": -1})
182
183
184@app.route('/activateuser', methods=['POST'])
185def activateuser():
186 try:
187 #print("Request: ", request)
188 content = request.json
189 print('Post content: ', content)
190 query1 = session.query(User).filter(
191 User.VerificationCode == content['vcode'])
192 user1 = query1.first()
193 if user1:
194 print('User id: ', user1.UserId)
195 user1.Active = 1
196 dt1 = dt.datetime.now()
197 # if (user1.Expire < dt1):
198 # return jsonify({"activated": -2})
199 user1.Expire = None
200 #user1.VerificationCode = None
201 session.add(user1)
202 session.commit()
203 return jsonify({"activated": 0, "email": user1.Email})
204 # (RuntimeError, TypeError, NameError, ValueError):
205 except Exception as inst:
206 exc_type, exc_obj, exc_tb = sys.exc_info()
207 print(type(inst))
208 print(inst.args)
209 print(inst)
210 print(exc_tb.tb_lineno)
211 return jsonify({"activated": -1})
212
213
214@app.route('/signup', methods=['POST'])
215def signup():
216 try:
217 content = request.json
218 print('Post content: ', content)
219 user = User()
220 user.Email = content['email']
221 user.UserName = content['email']
222 user.FirstName = content['firstname']
223 user.LastName = content['lastname']
224 salt = os.urandom(32)
225 key = hashlib.pbkdf2_hmac(
226 'sha256', content['password'].encode('utf-8'), salt, 100000)
227 print('salt: ', salt)
228 print('key: ', key)
229 storage = salt + key
230 user.Password = storage
231 user.Active = 0
232 user.IsFirstLogin = 0
233 user.IsExpire = 0
234 dt1 = dt.datetime.now()
235 #print("Expire date: ", dt1)
236 user.Expire = dt1 + timedelta(days=1)
237 user.VerificationCode = str(uuid.uuid4())
238 # session.add(user)
239 # session.commit()
240 print("user.Email: ", user.Email)
241 query1 = session.query(User).filter(User.UserName == user.Email)
242 user1 = query1.first()
243 if user1:
244 message = "http://localhost:5000/signin-dark?validation=" + user1.VerificationCode
245 sendEmail(user1.Email, message)
246 return jsonify({"uuid": user1.UserId})
247 return jsonify({"uuid": -1})
248 # (RuntimeError, TypeError, NameError, ValueError):
249 except Exception as inst:
250 exc_type, exc_obj, exc_tb = sys.exc_info()
251 print(type(inst))
252 print(inst.args)
253 print(inst)
254 print(exc_tb.tb_lineno)
255 return jsonify({"uuid": -2})
256
257
258@app.route("/login", methods=["GET", "POST"])
259def login():
260 # print db
261 #form = LoginForm()
262 print("request path", request.path)
263 print("request full path", request.full_path)
264 print("request script_root", request.script_root)
265 print("request base_url", request.base_url)
266 print("request url", request.url)
267 print("request url_root", request.url_root)
268 email = request.args.get('email')
269 password = request.args.get('password')
270
271 print("Form email: ", email) # form.email.data)
272 print("Form password: ", password) # form.password.data)
273 # if form.validate_on_submit():
274 # print("Form validated")
275
276 # User.query.get(email) #form.email.data)
277 query = session.query(User).filter(User.Email == email)
278 user = query.first()
279 if user:
280 salt_from_storage = user.Password[:32] # 32 is the length of the salt
281 pass_from_storage = user.Password[32:]
282 pass_calc = hashlib.pbkdf2_hmac(
283 'sha256', password.encode('utf-8'), salt_from_storage, 100000)
284 # if bcrypt.check_password_hash(user.password, form.password.data):
285 if pass_from_storage == pass_calc: # form.password.data:
286 user.IsAuthenticated = True
287 session.add(user)
288 session.commit()
289 login_user(user, remember=True)
290 query = session.query(UserSetting).filter(
291 UserSetting.UserRefId == user.UserId)
292 userset = query.first()
293 if not userset:
294 usersetting = UserSetting(UserRefId=user.UserId, CandleTime=0, CandleOpen=0,
295 CandleClose=0, CandleHigh=0, CandleLow=sys.maxsize, Interval='1D', Ticker='')
296 session.add(usersetting)
297 session.commit()
298 # pass_calc.decode("unicode_escape") }
299 res = {'email': user.Email, 'token': 'valid'}
300 # redirect("http://localhost:5000/exchange-dark") # url_for("bull.reports"))
301 return res
302 res = {'email': user.Email, 'token': 'notvalid'} # json.dumps(user)
303 return json.dumps(res)
304 # return redirect("http://localhost:5000/signin-dark/?valid=false") #"Not found" # render_template("login.html", form=form)
305
306
307@app.route("/logout", methods=["GET"])
308@login_required
309def logout():
310 """Logout the current user."""
311 print("Logout: ", current_user.get_id())
312 #user = current_user
313 #user.IsAuthenticated = False
314 # session.add(user)
315 # session.commit()
316 logout_user()
317 # res = {'email': user.Email, 'token': 'notvalid'} #json.dumps(user)
318 return "" # json.dumps(res)
319 # return redirect("/") #render_template("logout.html")
320
321
322@app.route('/', methods=['GET'])
323@login_required
324def home():
325 return "<h1>Distant Reading Archive</h1><p>This site is a prototype API for distant reading of science fiction novels.</p>"
326
327
328@app.route('/api/v1/resources/stocks/history', methods=['GET'])
329def api_history():
330 utc_start = request.args.get('start')
331 utc_end = request.args.get('end')
332 intPar = request.args.get('interval')
333 name = request.args.get('name')
334 name = name.lower().replace('/', '-')
335 if name != cache['ticker']:
336 cache['ticker'] = name
337
338 print('Start: ' + utc_start) # request.query_string.decode('utf-8'))
339 print('End: ' + utc_end)
340 print('Interval: ' + intPar)
341 print('Name: ' + name)
342 aapl = yf.Ticker(name) # "btc-usd")
343 aapl_historical = aapl.history(
344 start=utc_start, end=utc_end, interval=intPar).to_json()
345 # print(aapl_historical)
346 candles = []
347 y = json.loads(aapl_historical)
348 open = y['Open']
349 high = y['High']
350 low = y['Low']
351 close = y['Close']
352 volume = y['Volume']
353 #print('y: ', volume)
354 for val in open.keys():
355 utc_timeS = datetime.fromtimestamp(
356 int(val[0:10]), timezone.utc).strftime("%Y-%m-%d, %H:%M")
357 utc_time = datetime.strptime(utc_timeS, "%Y-%m-%d, %H:%M")
358 epoch_time = (utc_time - datetime(1970, 1, 1)).total_seconds()
359 a = Candle(int(epoch_time), round(float(open[val]), 2), round(float(high[val]), 2), round(
360 float(low[val]), 2), round(float(close[val]), 2), float(volume[val]))
361 a.volumefrom = round(float(volume[val]), 2)
362 a.volumeto = round(float(volume[val]), 2) + 5
363 candles.append(a)
364
365 #tcResponce = {'Aggregated': 'false', 'DATA': candles, 'FirstValueInArray': 'true', 'HasWarning': 'false', 'Response': 'Success', 'Type': 100 }
366 tcResponce = TCResponce()
367 #tcResponce.DATA = candles
368 #print("tcResponce: ", tcResponce)
369 json_string = json.dumps([ob.__dict__ for ob in candles])
370 #json_string = json.dumps([ob.__dict__ for ob in tcResponce])
371 tcResponce.Data = candles
372 y = tcResponce.toJSON() # json.dumps(tcResponce)
373 #print("tcResponce: ", tcResponce)
374 return y
375
376
377@app.route('/api/v1/resources/stocks/all', methods=['GET'])
378def api_all():
379 intPar = request.args.get('interval')
380 data = yf.download( # or pdr.get_data_yahoo(...
381 tickers="AAPL",
382 period="1d",
383 interval=intPar, # "1m",
384 group_by='ticker',
385 auto_adjust=True,
386 prepost=True,
387 threads=True,
388 proxy=None
389 ).to_json()
390
391 candles = []
392 y = json.loads(data)
393 open = y['Open']
394 high = y['High']
395 low = y['Low']
396 close = y['Close']
397 volume = y['Volume']
398 for val in open.keys():
399 utc_timeS = datetime.fromtimestamp(
400 int(val[0:10]), timezone.utc).strftime("%Y-%m-%d, %H:%M")
401 utc_time = datetime.strptime(utc_timeS, "%Y-%m-%d, %H:%M")
402 epoch_time = (utc_time - datetime(1970, 1, 1)).total_seconds()
403 a = Candle(int(epoch_time), round(float(open[val]), 2), round(float(high[val]), 2), round(
404 float(low[val]), 2), round(float(close[val]), 2), float(volume[val]))
405 candles.append(a)
406 json_string = json.dumps([ob.__dict__ for ob in candles])
407 return json_string
408
409
410@app.route('/api/v1/resources/stocks/last', methods=['GET'])
411def api_last():
412 #intPar = request.args.get('interval')
413 print("interval: ", cache['interval'])
414 data = yf.download( # or pdr.get_data_yahoo(...
415 tickers='btc-usd', # "AAPL",
416 period="1d",
417 interval=cache['interval'], # "1m",
418 group_by='ticker',
419 auto_adjust=True,
420 prepost=True,
421 threads=True,
422 proxy=None
423 ).to_json()
424
425 candles = []
426 y = json.loads(data)
427 open = y['Open']
428 high = y['High']
429 low = y['Low']
430 close = y['Close']
431 volume = y['Volume']
432 for val in open.keys():
433 utc_timeS = datetime.fromtimestamp(
434 int(val[0:10]), timezone.utc).strftime("%Y-%m-%d, %H:%M")
435 utc_time = datetime.strptime(utc_timeS, "%Y-%m-%d, %H:%M")
436 epoch_time = (utc_time - datetime(1970, 1, 1)).total_seconds()
437 #print('val: ', epoch_time)
438 #print("candle: ", open[val], high[val], low[val], close[val])
439 a = Candle(int(epoch_time), round(float(open[val]), 2), round(float(high[val]), 2), round(
440 float(low[val]), 2), round(float(close[val]), 2), float(volume[val]))
441 candles.append(a)
442 arr = [candles[len(candles) - 1]]
443 lastCandle = [candles[len(candles) - 2]]
444 if arr[0].time != cache['candle']:
445 cache['candle'] = arr[0].time
446 arr = lastCandle
447 json_string = json.dumps([ob.__dict__ for ob in arr])
448 print("Candle is changed")
449 return json_string
450
451 open = float(cache['open'])
452 close = float(cache['close'])
453 high = float(cache['high'])
454 low = float(cache['low'])
455
456 if arr[0].high > high:
457 cache['high'] = arr[0].high
458 else:
459 arr[0].high = high
460 if arr[0].low < low:
461 cache['low'] = arr[0].low
462 else:
463 arr[0].low = low
464
465 arr[0].open = lastCandle[0].close
466 json_string = json.dumps([ob.__dict__ for ob in arr])
467 return json_string
468
469
470@app.route('/api/v1/resources/stocks/setinterval', methods=['GET'])
471def api_setinterval():
472 intPar = request.args.get('interval')
473 cache['interval'] = intPar
474 print("[setInterval] interval: ", cache['interval'])
475 response = Response(status=200)
476 # need to set JSON like {'username': 'febin'}
477 return response
478
479
480@app.route('/api/v1/resources/stocks/gettickername', methods=['GET'])
481def api_gettickername():
482 print('ticker: ' + cache['ticker'])
483 return cache['ticker']
484
485
486def getHistoricalData(utc_start, utc_end, intPar, stock):
487 candles = []
488 #print('stock: ', stock)
489 aapl = yf.Ticker(stock) # "aapl")
490 aapl_historical = aapl.history(
491 start=utc_start, end=utc_end, interval=intPar).to_json()
492 y = json.loads(aapl_historical)
493 open = y['Open']
494 high = y['High']
495 low = y['Low']
496 close = y['Close']
497 volume = y['Volume']
498 #print('open: ', open)
499 for val in open.keys():
500 #print('val: ', open[val])
501 utc_timeS = datetime.fromtimestamp(
502 int(val[0:10]), timezone.utc).strftime("%Y-%m-%d, %H:%M")
503 utc_time = datetime.strptime(utc_timeS, "%Y-%m-%d, %H:%M")
504 epoch_time = (utc_time - datetime(1970, 1, 1)).total_seconds()
505 if open[val] is not None:
506 a = Candle(int(epoch_time), round(float(open[val]), 2), round(float(high[val]), 2), round(
507 float(low[val]), 2), round(float(close[val]), 2), float(volume[val]))
508 candles.append(a)
509 return candles
510
511
512@app.route('/api/v1/resources/stocks/calculatetrading', methods=['GET'])
513def api_check3bar():
514 utc_start = request.args.get('start')
515 utc_end = request.args.get('end')
516 intPar = request.args.get('interval')
517 algorithmCounter = request.args.get('algorithm', type=int)
518 stocks = request.args.get('stocks')
519
520 # print('Start: ' + utc_start) #request.query_string.decode('utf-8'))
521 #print('End: ' + utc_end)
522 #print('Interval: ' + intPar)
523
524 stocksArr = stocks.split(',')
525
526 times = []
527 result = []
528 chosenAlgorithm = check3bar
529 if algorithmCounter == 1:
530 chosenAlgorithm = check3bar
531 elif algorithmCounter == 2:
532 chosenAlgorithm = twoMinOpening
533 elif algorithmCounter == 3:
534 chosenAlgorithm = breakouts
535 elif algorithmCounter == 4:
536 chosenAlgorithm = shadow
537
538 for stock in stocksArr:
539 candles = getHistoricalData(utc_start, utc_end, intPar, stock)
540 times = chosenAlgorithm(candles)
541 userTimes = []
542 for val in times:
543 userTimes.append(datetime.fromtimestamp(
544 int(val), timezone.utc).strftime("%Y-%m-%d, %H:%M"))
545 result.append({stock: userTimes})
546
547 #print('times: ', userTimes)
548 json_string = json.dumps(result) # userTimes)
549 print('result: ', json_string)
550 return json_string
551
552#====== NEW CODE =====
553@app.route('/api/v1/resources/stocks/getStockNames', methods=['GET'])
554def getStockNames():
555
556 # get full stock info from wikipedia
557 resp = requests.get('http://en.wikipedia.org/wiki/List_of_S%26P_500_companies')
558 soup = bs.BeautifulSoup(resp.text, 'lxml')
559 table = soup.find('table', {'class': 'wikitable sortable'})
560
561 # get only the stock names from the data
562 tickers = []
563 for row in table.findAll('tr')[1:]:
564 ticker = row.findAll('td')[0].text
565 tickers.append(ticker[0:-1]) # slicing is for removing \n
566
567 # convert list to json
568 json_string = json.dumps(tickers)
569 return json_string
570#====== NEW CODE =====
571
572
573#endregion
574
575# app start
576app.run(port='5000')