import json from flask import Flask, render_template, request, redirect, jsonify from flask_cors import cross_origin from binance.enums import * from flask_sock import Sock # Handles all server side data and interactions. from data import BrighterData # Define app app = Flask(__name__) sock = Sock(app) # This object maintains all the application and historical data. # Access to server, local storage, other classes go through here. app_data = BrighterData() # app.config['SECRET_KEY'] = 'The quick brown fox jumps over the lazy dog' # app.config['CORS_HEADERS'] = 'Content-Type' # cors = CORS(app, resources={r"*": {"origins": "*"}}) @app.route('/') def index(): # Passes data into an HTML template and serves it to a locally hosted server rendered_data = app_data.get_rendered_data() js_data = app_data.get_js_init_data() return render_template('index.html', title=rendered_data['title'], my_balances=rendered_data['my_balances'], symbols=rendered_data['symbols'], intervals=rendered_data['intervals'], interval_state=rendered_data['chart_interval'], indicator_types=rendered_data['indicator_types'], indicator_list=rendered_data['indicator_list'], checked=rendered_data['enabled_indicators'], ma_vals=rendered_data['ma_vals'], js_data=js_data) @sock.route('/ws') def ws(sock): def json_msg_received(msg_obj): if 'message_type' in msg_obj: if msg_obj['message_type'] == 'candle_data': # Send the candle to the BrighterData_obj # and forward any returned data to the client. r_data = app_data.received_cdata(msg_obj['data']) if r_data: resp = { "reply": "updates", "data": r_data } sock.send(json.dumps(resp)) if msg_obj['message_type'] == 'request': if msg_obj['data'] == 'signals': signals = app_data.get_signals() if signals: resp = { "reply": "signals", "data": signals } resp = json.dumps(resp) sock.send(resp) elif msg_obj['data'] == 'strategies': strategies = app_data.get_strategies() if strategies: resp = { "reply": "strategies", "data": strategies } resp = json.dumps(resp) sock.send(resp) else: print('Warning: Unhandled request!') print(msg_obj['data']) if msg_obj['message_type'] == 'delete_signal': app_data.delete_signal(msg_obj['data']) if msg_obj['message_type'] == 'delete_strategy': app_data.delete_strategy(msg_obj['data']) if msg_obj['message_type'] == 'reply': print(msg_obj['rep']) print('Reply') if msg_obj['message_type'] == 'new_signal': # Send the data to the BrighterData_obj # and forward any returned data to the client. r_data = app_data.received_new_signal(msg_obj['data']) if r_data: resp = { "reply": "signal_created", "data": r_data } resp = json.dumps(resp) sock.send(resp) if msg_obj['message_type'] == 'new_strategy': # Send the data to the BrighterData_obj # and forward any returned data to the client. r_data = app_data.received_new_strategy(msg_obj['data']) if r_data: resp = { "reply": "strategy_created", "data": r_data } resp = json.dumps(resp) sock.send(resp) return # The rendered page connects to the exchange and relays the candle data back here # this socket also handles data and processing requests while True: msg = sock.receive() if msg: # If in json format the message gets converted into a dictionary # otherwise it is handled as a status signal from the client try: msg_obj = json.loads(msg) json_msg_received(msg_obj) except json.JSONDecodeError: print(f'Msg received from client: {msg}') @app.route('/buy', methods=['POST']) @cross_origin(origin='localhost', headers=['Content- Type', 'Authorization']) def buy(): print('This buy route is currently not being used.') # app_data.trades.new_trade( # symbol=request.form['symbol'], side=SIDE_BUY, # type=ORDER_TYPE_MARKET, quantity=request.form['quantity']) return redirect('/') @app.route('/sell', methods=['POST']) @cross_origin(origin='localhost', headers=['Content- Type', 'Authorization']) def sell(): print('This sell route is currently not being used.') # app_data.trades.new_trade( # symbol=request.form['symbol'], side=SIDE_SELL, # type=ORDER_TYPE_MARKET, quantity=request.form['quantity']) return redirect('/') @app.route('/settings', methods=['POST']) @cross_origin(origin='localhost', headers=['Content- Type', 'Authorization']) def settings(): setting = request.form['setting'] if setting == 'interval': interval_state = request.form['timeframe'] app_data.config.chart_interval = interval_state elif setting == 'trading_pair': trading_pair = request.form['trading_pair'] app_data.config.trading_pair = trading_pair elif setting == 'toggle_indicator': # Get a list of indicators to enable enabled_indicators = [] for i in request.form: if request.form[i] == 'indicator': enabled_indicators.append(i) # Set visibility for all indicators according to for indctr in app_data.indicators.indicator_list: if indctr in enabled_indicators: app_data.indicators.indicator_list[indctr]['visible'] = True else: app_data.indicators.indicator_list[indctr]['visible'] = False # Redirect without reloading history app_data.config.config_and_states('save') return redirect('/') elif setting == 'edit_indicator': if 'submit' in request.form: # Get the name of the indicator indicator = request.form['submit'] # Drop the name and action from our received data attributes = dict(list(request.form.items())[2:]) # All the numbers are string now so turn them back to (int) for a in attributes: if attributes[a].isdigit(): attributes[a] = int(attributes[a]) # if visible is unchecked it doesn't get sent by the form if 'visible' not in attributes: attributes.update({'visible': False}) # Set the data in indicators according to app_data.indicators.indicator_list[indicator] = attributes if 'delete' in request.form: indicator = request.form['delete'] # This will delete in both indicators and config. app_data.indicators.delete_indicator(indicator) # Redirect without reloading history app_data.config.config_and_states('save') return redirect('/') elif setting == 'new_indicator': if 'newi_name' in request.form: indcr = request.form['newi_name'] indtyp = request.form['newi_type'] properties = {} if request.form['new_prop_obj']: list_of_dic = json.loads(request.form['new_prop_obj']) # All the numbers are string now so turn them back to (int) properties = {} for prop in list_of_dic: # Get the key for this object key = next(iter(prop)) # access the value of this object value = prop[key] if value.isdigit(): value = int(value) properties[key] = value # Should create in indicators and update the list in config. app_data.indicators.create_indicator(name=indcr, itype=indtyp, properties=properties) else: print('ERROR SETTING VALUE') print(f'The string received by the server was: /n{request.form}') app_data.config.config_and_states('save') app_data.candles.set_candle_history() return redirect('/') @app.route('/history') @cross_origin(origin='localhost', headers=['Content- Type', 'Authorization']) def history(): symbol = app_data.config.trading_pair interval = app_data.config.chart_interval return jsonify(app_data.candles.get_candle_history(symbol, interval, 1000)) @app.route('/saved_data') @cross_origin(origin='localhost', headers=['Content- Type', 'Authorization']) def saved_data(): return jsonify(app_data.indicators.indicator_list) @app.route('/indicator_init') @cross_origin(origin='localhost', headers=['Content- Type', 'Authorization']) def indicator_init(): symbol = app_data.config.trading_pair interval = app_data.config.chart_interval d = app_data.indicators.get_indicator_data(symbol, interval, 800) return jsonify(d)