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