brighter-trading/Strategies.py

161 lines
6.5 KiB
Python

import json
class Strategies:
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):
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'