Classes implemented in python and javascript. UML class diagram. Rough sequence uml. TODO: local file getting dirty from refresh. Signals implemented. Strategies implemented. Trades are mostly implemented.

This commit is contained in:
Rob 2022-06-13 22:35:03 -03:00
parent 5d942a9c2c
commit 934a66012d
8 changed files with 487 additions and 59 deletions

View File

@ -95,6 +95,12 @@ class Signals:
def get_signals(self):
return self.signals
def get_signal_by_name(self, name):
for signal in self.signals:
if signal.name == name:
return signal
return None
def new_signal(self, data):
self.signals.append(Signal(**data))

View File

@ -1,15 +1,160 @@
import json
class Strategies:
def __init__(self, loaded_strats):
def __init__(self, loaded_strats, trades):
self.strat_list = loaded_strats
self.trades = trades
def new_strategy(self, data):
self.strat_list.append(data)
def delete_strategy(self, name):
for obj in self.strat_list:
if obj['name'] == name:
self.strat_list.remove(obj)
break
obj = self.get_strategy_by_name(name)
if obj:
self.strat_list.remove(obj)
def get_strategies(self):
return self.strat_list
def get_strategy_by_name(self, name):
for obj in self.strat_list:
if obj['name'] == name:
return obj
return False
def execute_cmd(self, strategy, action, cmd):
order_type = 'LIMIT'
if action == 'open_position':
# Attempt to create the trade.
trade_id = self.trades.new_trade(strategy['symbol'], cmd, order_type, strategy['trade_amount'])
# If the trade didn't fail.
if trade_id is not False:
# Set the active flag in strategy.
strategy['active'] = True
strategy['current_position'] += strategy['trade_amount']
strategy['trades'].append(trade_id)
return 'position_opened'
else:
print('Failed to place trade')
return 'failed'
if (action == 'stop_loss') or (action == 'take_profit'):
if action == 'stop_loss':
order_type = 'MARKET'
# Attempt to create the trade.
trade = self.trades.new_trade(strategy['symbol'], cmd, order_type, strategy['current_position'])
# If the trade didn't fail.
if trade is not False:
# Set the active flag in strategy.
strategy['active'] = False
strategy['current_position'] = 0
return 'position_closed'
else:
print('Failed to place trade')
return 'failed'
print('Strategies.execute_cmd: Invalid action received.')
return 'failed'
def update(self, signals):
"""
Receives a reference to updated signal data. Loops through all
published strategies and evaluates conditions against the data.
This function returns a list of strategies and action commands.
"""
# Object containing data to return to function caller.
actions = {}
# Loop through all the published strategies.
for strategy in self.strat_list:
# Process any take_profit strategy.
if strategy['type'] == 'take_profit':
action, cmd = self.eval_tp_stg(strategy, signals)
if action == 'do_nothing':
return False
else:
# Execute the command.
actions[strategy['name']] = self.execute_cmd(strategy, action, cmd)
else:
print(f"Strategy.update: Strategy of type {strategy['type']} - not yet implemented.")
if len(actions) != 0:
return actions
else:
return False
def eval_tp_stg(self, strategy, signals):
"""
:param strategy: str: The strategy to evaluate.
:param signals: Signals: A reference to an object that handles current signal states.
:return action: Action required based on evaluation. format{cmd:str, amount:real, margin:int}
"""
def condition_satisfied(sig_name, vlue):
signal = signals.get_signal_by_name(sig_name)
if vlue == json.dumps(signal.state):
return True
else:
return False
def all_conditions_met(conditions):
if len(conditions) < 1:
print(f"no trade-in conditions supplied: {strategy['name']}")
return False
# Evaluate all conditions and return false if any are un-met.
for trigger_signal in conditions.keys():
trigger_value = conditions[trigger_signal]
# Compare this signal's state with the trigger_value
if not condition_satisfied(trigger_signal, trigger_value):
return False
return True
def trade_out_condition_met(condition_type):
if strategy[condition_type]['typ'] == 'conditional':
signal_name = strategy[condition_type]['trig']
signal_value = strategy[condition_type]['val']
if condition_satisfied(signal_name, signal_value):
# If the condition is met trade-out.
return True
else:
return False
else:
if strategy[condition_type]['typ'] != 'value':
raise ValueError('trade_out_condition_met: invalid condition_type')
if condition_type == 'take_profit':
# If the profit condition is met send command to take profit.
if strategy['gross_profit'] > strategy['take_profit']['val']:
return True
else:
return False
else:
# If the loss condition is met, return a trade-out command.
if strategy['gross_loss'] < strategy['stop_loss']['val']:
return True
else:
return False
trade_in_cmd = strategy['side']
if strategy['side'] == 'buy':
trade_out_cmd = 'sell'
else:
trade_out_cmd = 'buy'
# If trade-in conditions are met.
if all_conditions_met(strategy['trd_in_conds']):
# If the new trade wouldn't exceed max_position. Return a trade-in command.
proposed_position_size = strategy['current_position'] + strategy['trade_amount']
if proposed_position_size < strategy['max_position']:
return 'enter_position', trade_in_cmd
# If strategy is active test the take-profit or stop-loss conditions.
if strategy['active']:
# Conditional take-profit trades-out if a signals equals a set value.
if trade_out_condition_met('take_profit'):
return 'take_profit', trade_out_cmd
# Conditional stop-loss trades-outs if a signals value equals a set value.
if trade_out_condition_met('stop_loss'):
return 'stop_loss', trade_out_cmd
# No conditions were met.
print('Strategies were updated and nothing to do.')
return 'do_nothing', 'nothing'

81
app.py
View File

@ -4,15 +4,17 @@ 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
import data as bt
# *NOT DONE YET*
import trade
# 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'
@ -21,8 +23,8 @@ sock = Sock(app)
@app.route('/')
def index():
# Passes data into an HTML template and serves it to a locally hosted server
rendered_data = bt.app_data.get_rendered_data()
js_data = bt.app_data.get_js_init_data()
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'],
@ -43,7 +45,7 @@ def ws(sock):
if msg_obj['message_type'] == 'candle_data':
# Send the candle to the BrighterData_obj
# and forward any returned data to the client.
r_data = bt.app_data.received_cdata(msg_obj['data'])
r_data = app_data.received_cdata(msg_obj['data'])
if r_data:
resp = {
"reply": "updates",
@ -53,7 +55,7 @@ def ws(sock):
if msg_obj['message_type'] == 'request':
if msg_obj['data'] == 'signals':
signals = bt.app_data.get_signals()
signals = app_data.get_signals()
if signals:
resp = {
"reply": "signals",
@ -62,7 +64,7 @@ def ws(sock):
resp = json.dumps(resp)
sock.send(resp)
elif msg_obj['data'] == 'strategies':
strategies = bt.app_data.get_strategies()
strategies = app_data.get_strategies()
if strategies:
resp = {
"reply": "strategies",
@ -75,10 +77,10 @@ def ws(sock):
print(msg_obj['data'])
if msg_obj['message_type'] == 'delete_signal':
bt.app_data.delete_signal(msg_obj['data'])
app_data.delete_signal(msg_obj['data'])
if msg_obj['message_type'] == 'delete_strategy':
bt.app_data.delete_strategy(msg_obj['data'])
app_data.delete_strategy(msg_obj['data'])
if msg_obj['message_type'] == 'reply':
print(msg_obj['rep'])
@ -87,7 +89,7 @@ def ws(sock):
if msg_obj['message_type'] == 'new_signal':
# Send the data to the BrighterData_obj
# and forward any returned data to the client.
r_data = bt.app_data.received_new_signal(msg_obj['data'])
r_data = app_data.received_new_signal(msg_obj['data'])
if r_data:
resp = {
"reply": "signal_created",
@ -99,7 +101,7 @@ def ws(sock):
if msg_obj['message_type'] == 'new_strategy':
# Send the data to the BrighterData_obj
# and forward any returned data to the client.
r_data = bt.app_data.received_new_strategy(msg_obj['data'])
r_data = app_data.received_new_strategy(msg_obj['data'])
if r_data:
resp = {
"reply": "strategy_created",
@ -126,19 +128,20 @@ def ws(sock):
@app.route('/buy', methods=['POST'])
@cross_origin(origin='localhost', headers=['Content- Type', 'Authorization'])
def buy():
print(request.form) # Debug ******
trade.order(
symbol=request.form['symbol'], side=SIDE_BUY,
type=ORDER_TYPE_MARKET, quantity=request.form['quantity'])
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():
trade.order(
symbol=request.form['symbol'], side=SIDE_SELL,
type=ORDER_TYPE_MARKET, quantity=request.form['quantity'])
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('/')
@ -148,10 +151,10 @@ def settings():
setting = request.form['setting']
if setting == 'interval':
interval_state = request.form['timeframe']
bt.app_data.config.chart_interval = interval_state
app_data.config.chart_interval = interval_state
elif setting == 'trading_pair':
trading_pair = request.form['trading_pair']
bt.app_data.config.trading_pair = trading_pair
app_data.config.trading_pair = trading_pair
elif setting == 'toggle_indicator':
# Get a list of indicators to enable
enabled_indicators = []
@ -159,13 +162,13 @@ def settings():
if request.form[i] == 'indicator':
enabled_indicators.append(i)
# Set visibility for all indicators according to <enabled_indicators>
for indctr in bt.app_data.indicators.indicator_list:
for indctr in app_data.indicators.indicator_list:
if indctr in enabled_indicators:
bt.app_data.indicators.indicator_list[indctr]['visible'] = True
app_data.indicators.indicator_list[indctr]['visible'] = True
else:
bt.app_data.indicators.indicator_list[indctr]['visible'] = False
app_data.indicators.indicator_list[indctr]['visible'] = False
# Redirect without reloading history
bt.app_data.config.config_and_states('save')
app_data.config.config_and_states('save')
return redirect('/')
elif setting == 'edit_indicator':
@ -182,14 +185,14 @@ def settings():
if 'visible' not in attributes:
attributes.update({'visible': False})
# Set the data in indicators according to <attributes>
bt.app_data.indicators.indicator_list[indicator] = attributes
app_data.indicators.indicator_list[indicator] = attributes
if 'delete' in request.form:
indicator = request.form['delete']
# This will delete in both indicators and config.
bt.app_data.indicators.delete_indicator(indicator)
app_data.indicators.delete_indicator(indicator)
# Redirect without reloading history
bt.app_data.config.config_and_states('save')
app_data.config.config_and_states('save')
return redirect('/')
elif setting == 'new_indicator':
@ -210,35 +213,35 @@ def settings():
value = int(value)
properties[key] = value
# Should create in indicators and update the list in config.
bt.app_data.indicators.create_indicator(name=indcr, itype=indtyp, properties=properties)
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}')
bt.app_data.config.config_and_states('save')
bt.app_data.candles.set_candle_history()
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 = bt.app_data.config.trading_pair
interval = bt.app_data.config.chart_interval
return jsonify(bt.app_data.candles.get_candle_history(symbol, interval, 1000))
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(bt.app_data.indicators.indicator_list)
return jsonify(app_data.indicators.indicator_list)
@app.route('/indicator_init')
@cross_origin(origin='localhost', headers=['Content- Type', 'Authorization'])
def indicator_init():
symbol = bt.app_data.config.trading_pair
interval = bt.app_data.config.chart_interval
d = bt.app_data.indicators.get_indicator_data(symbol, interval, 800)
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)

22
data.py
View File

@ -7,6 +7,7 @@ from Configuration import Configuration
from exchange_info import ExchangeInfo
from indicators import Indicators
from Signals import Signals
from trade import Trades
import json
@ -38,7 +39,10 @@ class BrighterData:
self.exchange_info = ExchangeInfo(self.client)
# Object that maintains the strategies data
self.strategies = Strategies(self.config.strategies_list)
self.trades = Trades(self.client)
# Object that maintains the strategies data
self.strategies = Strategies(self.config.strategies_list, self.trades)
def get_js_init_data(self):
"""Returns a JSON object of initialization data
@ -80,10 +84,24 @@ class BrighterData:
i_updates = self.indicators.update_indicators()
# Process the signals based on the last indicator updates.
state_changes = self.signals.process_all_signals(self.indicators)
# Update the trades instance.
trade_updates = self.trades.update(cdata)
# Update the strategies instance.
stg_updates = self.strategies.update(self.signals)
# Format and return an update object.
updates = {'i_updates': i_updates}
if state_changes:
print(state_changes)
updates.update({'s_updates': state_changes})
if stg_updates:
print(stg_updates)
updates.update({'stg_updts': stg_updates})
if trade_updates:
print(trade_updates)
updates.update({'trade_updts': trade_updates})
return updates
def received_new_signal(self, data):
@ -136,5 +154,3 @@ class BrighterData:
# Delete the signal from the configuration file.
self.config.remove('signals', signal_name)
app_data = BrighterData()

View File

@ -7,7 +7,12 @@ class Alert{
// Other info in the alert.
this.state = state;
// The alert messages.
this.msg = 'Signal state change: ' + this.source + ' = ' + this.state;
if (alert_type=='signal'){
this.msg = 'Signal state change: ' + this.source + ' = ' + this.state;
}
if (alert_type=='strategy'){
this.msg = 'Strategy alert: ' + this.source + ' = ' + this.state;
}
}
alert_source(){
return this.source;
@ -44,6 +49,14 @@ class Alerts {
this.update_html();
}
if (alert_type == 'strategy'){
// If the alert_type is strategy then data will
// contain a list of objects with format: { name: str, state: bool }
console.log('publishing strategy alerts')
this.alerts.push( new Alert('strategy', 'source', data) );
this.update_html();
}
}
update_html(){

View File

@ -61,6 +61,18 @@ class Strategies {
strat.type = document.getElementById('strat_type').value;
strat.side = document.getElementById('trade_in_side').value;
strat.margin = document.getElementById('margin_select').value;
strat.trade_amount = document.getElementById('trade_amount').value;
strat.max_position = document.getElementById('strgy_total').value;
strat.trading_fee = document.getElementById('fee').value;
strat.max_loss = document.getElementById('max_loss').value;
strat.symbol = window.UI.data.trading_pair;
strat.net_profit = 0;
strat.gross_profit = 0;
strat.net_loss = 0;
strat.gross_loss = 0;
strat.current_position = 0;
strat.current_value = 0;
strat.active = false;
strat.trd_in_conds = {};
let conds = Array.from(document.querySelectorAll('#trade_in_cond>li'));
for (let cond of conds){
@ -93,6 +105,15 @@ class Strategies {
window.UI.data.comms.send_to_app( "new_strategy", strat);
this.close_form();
}
update_received(stg_updts){
if ( 'cmd' in stg_updts) {
let alert =
window.UI.alerts.publish_alerts('strategy', stg_updts);
this.executeCmd(stg_updts.cmd);
}
console.log('recieved stategy update.');
console.log(stg_updts);
}
set_data(strats){
for (let strat of strats){
// Add the strategy to the instance list.
@ -128,7 +149,7 @@ class Strategies {
parent.appendChild(lbl);
parent.appendChild(select);
}
val_input(name, label, parent, min, max, i_val){
val_input(name, label, parent, min, max, i_val, style = null){
/* Create an input element.
name: name and id of the element.
label: text displayed beside the element.
@ -144,8 +165,11 @@ class Strategies {
input.id = name;
input.type = 'number';
input.min = min;
input.max = max;
if (max) {input.max = max;}
input.value = i_val;
if (style){
input.style = style;
}
parent.appendChild(lbl);
parent.appendChild(input);
@ -170,12 +194,30 @@ class Strategies {
// Clear previous content.
this.clear_innerHTML(options);
// Add a horizontal rule.
options.appendChild(document.createElement('hr'));
//Create a drop down for buy/sell option
this.dropDown('trade_in_side','Side:', options, ['buy','sell']);
//Create an input for margin trading value. (1-100)
//Create an input for the margin. (1-100)
this.val_input('margin_select', 'Margin:', options, 1,100, 50);
// Add a line break.
options.appendChild( document.createElement('br') );
//Create an input for the amount. (1-*)
this.val_input('trade_amount', 'Trade amount:', options, 1, 0, 1,'width: 54px;');
//Create an input for the amount. (1-*)
this.val_input('strgy_total', 'Strategy total:', options, 1, 0, 10, 'width: 54px;');
// Add a line break.
options.appendChild( document.createElement('br') );
//Create an input for the fee. (0.01-1)
this.val_input('fee', 'Trading Fee:', options, 0.001, 1, 0.025);
// Create a un ordered list to hold the conditions of trading in.
let ul_in_cond = document.createElement('ul');
ul_in_cond.id ='trade_in_cond';
@ -251,6 +293,11 @@ class Strategies {
// Add a horizontal rule.
options.appendChild(document.createElement('hr'));
// Create an input for tolerable loss.
this.val_input('max_loss', 'Max loss :', options, 1,100, 50);
// Add a line break.
options.appendChild(document.createElement('br'));
//Create a drop down for Stop Loss type.
this.dropDown('loss_typ','Stop-Loss type:', options, ['value', 'conditional']);
// Add and onchange function to show and hide some options.
@ -268,7 +315,7 @@ class Strategies {
// Add a line break.
options.appendChild( document.createElement('br') );
// Create an input for take profit value.
// Create an input for stop loss value.
this.val_input('loss_val', 'Loss %:', options, 1,100, 50);
// Set display to visible.
this.hideShowTags(['loss_val_lbl','loss_val'], 'show');

View File

@ -80,6 +80,13 @@ class Comms {
window.UI.signals.update_signal_states(updates);
window.UI.alerts.publish_alerts('signal_changes', updates);
}
if ('stg_updts' in msg.data){
/* If the received message contains signal updates.
Forward them to the signals instance. These messages
only arrive if a signal state changes. */
let stg_updts = msg.data['stg_updts'];
window.UI.strats.update_received(stg_updts);
}
}else if (msg.reply == 'signals'){
/* On initialization the server will send a list of signals loaded from file.
Forward this to the signals instance.*/

205
trade.py
View File

@ -1,9 +1,200 @@
import data as bt_data
import json
import requests
from datetime import datetime
def order(symbol, side, type, quantity):
try:
order = bt_data.client.create_order(symbol, side, type, quantity)
# Report error if order fails
except Exception as e:
flash(e.message, "error")
class Trade:
def __init__(self, symbol, side, order_type, position_size, price):
"""
:param symbol: The symbol of the trading pair.
:param side: BUY|SELL
:param order_type: LIMIT|MARKET
:param position_size: Value in USD
:param price: Asking price for LIMIT orders.
"""
# Returns a datetime object containing the local date and time
self.timestamp = datetime.now()
self.symbol = symbol
self.side = side
self.order_type = order_type
self.position_size = position_size
# Flag set once order is placed successfully.
self.order_placed = False
# Order info returned when order is placed.
self.order = None
# Flag set once order is filled
self.order_filled = False
# This flag is set when the trade is closed out.
self.trade_closed = False
# Opening value of the asset.
self.opening_price = price
# Current value
self.value = 0
# Profit or Loss
self.profit_loss = 0
# Profit or Loss in percentage.
self.pl_percentage = 0
def update(self, current_price):
# Utility function.
def percent(part, whole):
if whole == 0:
return 0
pct = 100 * float(part) / float(whole)
return pct
# Set the current value and profit/loss
initial_value = self.position_size * self.opening_price
self.value = self.position_size * current_price
if self.side == 'buy':
self.profit_loss = self.value - initial_value
else:
self.profit_loss = initial_value - self.value
self.pl_percentage = percent(self.profit_loss, initial_value)
return self.profit_loss
class Trades:
def __init__(self, client):
"""
:param client: The socket connection to the exchange.
"""
# Socket connection to the exchange.
self.client = client
# For automating limit orders offset the current price by 1/100 percent.
self.offset_amount = 0.0001
# Exchange fees. Maybe these can be fetched from the server?
self.exchange_fees = {'maker': 0.01, 'taker': 0.05}
# Hedge mode allows long and shorts to be placed simultaneously.
self.hedge_mode = False
# If hedge mode is disabled this is either {'buy','sell'}.
self.side = None
# A list of unfilled trades.
self.unfilled_trades = []
# A list of filled trades.
self.filled_trades = []
# A completed trades.
self.closed_trades = []
# Number of open trades.
self.num_trades = 0
# The quantity sum of all open trades.
self.total_position = 0
# The value of all open trades in USD.
self.total_position_value = 0
# Info on all futures symbols
self.info = client.futures_exchange_info()
# Dictionary of places the exchange requires after the decimal for all symbols.
self.symbols_n_precision = {}
for item in self.info['symbols']:
self.symbols_n_precision[item['symbol']] = item['quantityPrecision']
def update(self, cdata):
r_update = []
# Check if any unfilled orders are now filled.
for trade in self.unfilled_trades:
if not trade.order_filled:
order = self.client.get_order(symbol=trade.symbol, orderId=trade.order['orderId'])
if order['status'] == 'FILLED':
trade.order_filled = True
self.filled_trades.append(trade)
r_update.append({trade.timestamp: 'filled'})
# Delete filled trades from unfilled_trades
self.unfilled_trades[:] = (t for t in self.unfilled_trades if t.order_filled is False)
for trade in self.filled_trades:
# Update the open trades.
ret = trade.update(cdata['close'])
r_update.append({trade.timestamp: {'pl': ret}})
# If a trade has been closed...
if trade.trade_closed:
self.closed_trades.append(trade)
# Notify caller
r_update.append({trade.timestamp: 'closed'})
# Delete closed trades from filled_trades
self.filled_trades[:] = (t for t in self.filled_trades if t.trade_closed is False)
return r_update
def new_trade(self, symbol, side, order_type, usd, price=None):
# If hedge mode is disabled return False if trade is on opposite side.
if self.hedge_mode is False:
if self.side is None:
self.side = side
if self.side != side:
return False
# If no price is given, set the asking price to be offset by a small amount.
if price is None:
offset = self.get_price(symbol) * self.offset_amount
if side == 'buy':
price = f'-{offset}'
else:
price = f'+{offset}'
# A relative limit order may be set by passing a string preceded with a +/-
if type(price) == str:
if ('+' in price) or ('-' in price):
price = self.get_price(symbol) + float(price)
else:
price = float(price)
position_size = usd / price
# The required level of precision for this trading pair.
precision = self.symbols_n_precision[symbol]
# String representing the order amount formatted to the level of precision defined above.
order_amount = "{:0.0{}f}".format(position_size, precision)
# Create a trade and place the order.
trade = Trade(symbol, side, order_type, order_amount, price)
order = self.place_order(trade)
# If the order successfully placed store the trade.
if order:
# Set th order placed flag.
trade.order_placed = True
# Save the order info in the trade object.
trade.order = order
# Update the trades instance.
self.num_trades += 1
self.unfilled_trades.append(trade)
print(order)
return trade
else:
return False
@staticmethod
def get_price(symbol):
# Todo: Make sure im getting the correct market price for futures.
request = requests.get(f'https://api.binance.com/api/v3/ticker/price?symbol={symbol}')
json_obj = json.loads(request.text)
return json_obj['price']
def place_order(self, trade):
if trade.order_type == 'MARKET':
try:
order = self.client.create_test_order(symbol=trade.symbol,
side=trade.side,
type=trade.order_type,
quantity=trade.position_size)
print('!!!Order created!!!')
return order
# Report error if order fails
except Exception as e:
print(e, "error")
return None
elif trade.order_type == 'LIMIT':
try:
order = self.client.create_test_order(
symbol=trade.symbol, side=trade.side, type=trade.order_type,
timeInForce='GTC', quantity=trade.position_size,
price=trade.opening_price)
return order
# If order fails
except Exception as e:
print(e, "error")
return None
else:
print(f'Trade: No Implementation for trade.order: {trade.order_type}')
return None