Skip to content

Commit

Permalink
Allow conditional notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
xinshen committed Aug 1, 2020
1 parent 51d184e commit 069cc31
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 12 deletions.
2 changes: 1 addition & 1 deletion app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def main():
key: market_data[exchange][key] for key in chunk}

notifier = Notifier(
config.notifiers, config.indicators, market_data_chunk)
config.notifiers, config.indicators, config.conditionals, market_data_chunk)
behaviour = Behaviour(config, exchange_interface, notifier)

workerName = "Worker-{}".format(num)
Expand Down
5 changes: 5 additions & 0 deletions app/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ def __init__(self):
self.exchanges = user_config['exchanges']
else:
self.exchanges = dict()

if 'conditionals' in user_config:
self.conditionals = user_config['conditionals']
else:
self.conditionals = None

for exchange in ccxt.exchanges:
if exchange not in self.exchanges:
Expand Down
67 changes: 57 additions & 10 deletions app/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
from time import sleep

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np
import pandas as pd
Expand All @@ -36,12 +35,14 @@
from notifiers.twilio_client import TwilioNotifier
from notifiers.webhook_client import WebhookNotifier

matplotlib.use('Agg')


class Notifier(IndicatorUtils):
"""Handles sending notifications via the configured notifiers
"""

def __init__(self, notifier_config, indicator_config, market_data):
def __init__(self, notifier_config, indicator_config, conditional_config, market_data):
"""Initializes Notifier class
Args:
Expand All @@ -51,6 +52,7 @@ def __init__(self, notifier_config, indicator_config, market_data):
self.logger = structlog.get_logger()
self.notifier_config = notifier_config
self.indicator_config = indicator_config
self.conditional_config = conditional_config
self.market_data = market_data
self.last_analysis = dict()
self.enable_charts = False
Expand Down Expand Up @@ -147,13 +149,58 @@ def notify_all(self, new_analysis):
for market_pair in messages[exchange]:
_messages = messages[exchange][market_pair]

for candle_period in _messages:
if not isinstance(_messages[candle_period], list) or len(_messages[candle_period]) == 0:
continue
if self.conditional_config:
self.notify_conditional(exchange, market_pair, _messages)
else:
for candle_period in _messages:
if not isinstance(_messages[candle_period], list) or len(_messages[candle_period]) == 0:
continue

self.notify_all_messages(
exchange, market_pair, candle_period, _messages[candle_period])
sleep(4)

def notify_conditional(self, exchange, market_pair, messages):
status = ['hot', 'cold']

for condition in self.conditional_config:
x = 0
nb_conditions = 0
new_message = {}
new_message['values'] = []
new_message['indicator'] = []
for candle_period in messages:
if messages[candle_period]:
new_message['exchange'] = messages[candle_period][0]['exchange']
new_message['market'] = messages[candle_period][0]['market']
new_message['base_currency'] = messages[candle_period][0]['base_currency']
new_message['quote_currency'] = messages[candle_period][0]['quote_currency']
for msg in messages[candle_period]:
for stat in status:
if msg['status'] == stat:
try:
for indicator in condition[stat]:
if msg['indicator'] in indicator.keys():
if indicator[msg['indicator']] == msg['indicator_number']:
new_message['values'].append(
msg['values'])
new_message['indicator'].append(
msg['indicator'])
x += 1
except:
pass
for stat in status:
try:
nb_conditions += len(condition[stat])
except:
pass

self.notify_all_messages(
exchange, market_pair, candle_period, _messages[candle_period])
sleep(4)
if x == nb_conditions and x != 0:
new_message['status'] = condition['label']
self.notify_discord([new_message])
self.notify_webhook([new_message], None)
self.notify_telegram([new_message], None)
self.notify_stdout([new_message])

def notify_all_messages(self, exchange, market_pair, candle_period, messages):
chart_file = None
Expand Down Expand Up @@ -682,7 +729,7 @@ def create_charts(self, messages):
except Exception as e:
self.logger.info(
'Error creating chart for %s %s', market_pair, candle_period)
self.logger.exception(e)
self.logger.exception(e)

def create_chart(self, exchange, market_pair, candle_period, candles_data):

Expand Down
119 changes: 118 additions & 1 deletion docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,125 @@ crossovers:
crossed_signal: sma
```
# 8) Conditionals
# 8) Examples
It's allowing you to receive notifications, only if one or more conditions are respected.
Use case examples:
- Receive a buy notification if rsi is cold and bollinger is hot and aroon is cold.
- Receive a sell notification if 1d rsi is hot and 1h rsi is hot and bollinger is cold and aroon is hot.
**You will not receive notifications if all conditions, of one conditionnal, are not met.**
## Example
```yml
settings:
log_level: INFO
update_interval: 120
start_worker_interval: 2
market_data_chunk_size: 1
timezone: Europe/Paris

exchanges:
kraken:
required:
enabled: true
all_pairs:
- USD

indicators:
rsi:
- enabled: true
alert_enabled: true
alert_frequency: always
signal:
- rsi
hot: 30
cold: 70
candle_period: 1h
period_count: 14
- enabled: true
alert_enabled: true
alert_frequency: always
signal:
- rsi
hot: 40
cold: 60
candle_period: 1d
period_count: 14
bollinger:
- enabled: true
candle_period: 1h
alert_enabled: true
alert_frequency: always
period_count: 25
std_dev: 2.5
signal:
- low_band
- close
- up_band
mute_cold: false
- enabled: true
candle_period: 1d
alert_enabled: true
alert_frequency: always
period_count: 25
std_dev: 2.5
signal:
- low_band
- close
- up_band
mute_cold: false
aroon_oscillator:
- enabled: true
alert_enabled: true
alert_frequency: always
sma_vol_period: 50
period_count: 14
signal:
- aroon
candle_period: 1h

conditionals:
- label: "Signal to buy"
hot:
- rsi: 0
- rsi: 1
cold:
- bollinger: 0
- label: "Signal to buy"
hot:
- rsi: 1
- label: "Signal to sell"
cold:
- rsi: 1
- rsi: 0
hot:
- aroon_oscillator: 0

notifiers:
telegram:
required:
token: X
chat_id: Y
optional:
parse_mode: html
template: "[{{market}}] {{indicator}} {{status}} {{values}} {{ '\n' -}}"
```
## Template value available
- values
- indicator
- exchange
- market
- base_currency
- quote_currency
- status
The `status` will be the string set in `label`.

# 9) Examples
Putting it all together an example config.yml might look like the config below if you want to use the default settings with bittrex

```yml
Expand Down

1 comment on commit 069cc31

@zooz124
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I really apreciate your work. Does the conditionals work? i changed all the files and tries with a simple example but the bot won't start.
I wish you could help me please. Thanks.

Please sign in to comment.