Skip to content

Commit 069cc31

Browse files
author
xinshen
committed
Allow conditional notifications
1 parent 51d184e commit 069cc31

File tree

4 files changed

+181
-12
lines changed

4 files changed

+181
-12
lines changed

app/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def main():
5050
key: market_data[exchange][key] for key in chunk}
5151

5252
notifier = Notifier(
53-
config.notifiers, config.indicators, market_data_chunk)
53+
config.notifiers, config.indicators, config.conditionals, market_data_chunk)
5454
behaviour = Behaviour(config, exchange_interface, notifier)
5555

5656
workerName = "Worker-{}".format(num)

app/conf.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ def __init__(self):
5858
self.exchanges = user_config['exchanges']
5959
else:
6060
self.exchanges = dict()
61+
62+
if 'conditionals' in user_config:
63+
self.conditionals = user_config['conditionals']
64+
else:
65+
self.conditionals = None
6166

6267
for exchange in ccxt.exchanges:
6368
if exchange not in self.exchanges:

app/notification.py

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@
1010
from time import sleep
1111

1212
import matplotlib
13-
matplotlib.use('Agg')
14-
import matplotlib.pyplot as plt
1513
import matplotlib.dates as mdates
14+
import matplotlib.pyplot as plt
1615
import matplotlib.ticker as mticker
1716
import numpy as np
1817
import pandas as pd
@@ -36,12 +35,14 @@
3635
from notifiers.twilio_client import TwilioNotifier
3736
from notifiers.webhook_client import WebhookNotifier
3837

38+
matplotlib.use('Agg')
39+
3940

4041
class Notifier(IndicatorUtils):
4142
"""Handles sending notifications via the configured notifiers
4243
"""
4344

44-
def __init__(self, notifier_config, indicator_config, market_data):
45+
def __init__(self, notifier_config, indicator_config, conditional_config, market_data):
4546
"""Initializes Notifier class
4647
4748
Args:
@@ -51,6 +52,7 @@ def __init__(self, notifier_config, indicator_config, market_data):
5152
self.logger = structlog.get_logger()
5253
self.notifier_config = notifier_config
5354
self.indicator_config = indicator_config
55+
self.conditional_config = conditional_config
5456
self.market_data = market_data
5557
self.last_analysis = dict()
5658
self.enable_charts = False
@@ -147,13 +149,58 @@ def notify_all(self, new_analysis):
147149
for market_pair in messages[exchange]:
148150
_messages = messages[exchange][market_pair]
149151

150-
for candle_period in _messages:
151-
if not isinstance(_messages[candle_period], list) or len(_messages[candle_period]) == 0:
152-
continue
152+
if self.conditional_config:
153+
self.notify_conditional(exchange, market_pair, _messages)
154+
else:
155+
for candle_period in _messages:
156+
if not isinstance(_messages[candle_period], list) or len(_messages[candle_period]) == 0:
157+
continue
158+
159+
self.notify_all_messages(
160+
exchange, market_pair, candle_period, _messages[candle_period])
161+
sleep(4)
162+
163+
def notify_conditional(self, exchange, market_pair, messages):
164+
status = ['hot', 'cold']
165+
166+
for condition in self.conditional_config:
167+
x = 0
168+
nb_conditions = 0
169+
new_message = {}
170+
new_message['values'] = []
171+
new_message['indicator'] = []
172+
for candle_period in messages:
173+
if messages[candle_period]:
174+
new_message['exchange'] = messages[candle_period][0]['exchange']
175+
new_message['market'] = messages[candle_period][0]['market']
176+
new_message['base_currency'] = messages[candle_period][0]['base_currency']
177+
new_message['quote_currency'] = messages[candle_period][0]['quote_currency']
178+
for msg in messages[candle_period]:
179+
for stat in status:
180+
if msg['status'] == stat:
181+
try:
182+
for indicator in condition[stat]:
183+
if msg['indicator'] in indicator.keys():
184+
if indicator[msg['indicator']] == msg['indicator_number']:
185+
new_message['values'].append(
186+
msg['values'])
187+
new_message['indicator'].append(
188+
msg['indicator'])
189+
x += 1
190+
except:
191+
pass
192+
for stat in status:
193+
try:
194+
nb_conditions += len(condition[stat])
195+
except:
196+
pass
153197

154-
self.notify_all_messages(
155-
exchange, market_pair, candle_period, _messages[candle_period])
156-
sleep(4)
198+
if x == nb_conditions and x != 0:
199+
new_message['status'] = condition['label']
200+
self.notify_discord([new_message])
201+
self.notify_webhook([new_message], None)
202+
self.notify_telegram([new_message], None)
203+
self.notify_stdout([new_message])
157204

158205
def notify_all_messages(self, exchange, market_pair, candle_period, messages):
159206
chart_file = None
@@ -682,7 +729,7 @@ def create_charts(self, messages):
682729
except Exception as e:
683730
self.logger.info(
684731
'Error creating chart for %s %s', market_pair, candle_period)
685-
self.logger.exception(e)
732+
self.logger.exception(e)
686733

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

docs/config.md

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,125 @@ crossovers:
508508
crossed_signal: sma
509509
```
510510
511+
# 8) Conditionals
511512
512-
# 8) Examples
513+
It's allowing you to receive notifications, only if one or more conditions are respected.
514+
515+
Use case examples:
516+
- Receive a buy notification if rsi is cold and bollinger is hot and aroon is cold.
517+
- Receive a sell notification if 1d rsi is hot and 1h rsi is hot and bollinger is cold and aroon is hot.
518+
519+
**You will not receive notifications if all conditions, of one conditionnal, are not met.**
520+
521+
## Example
522+
523+
```yml
524+
settings:
525+
log_level: INFO
526+
update_interval: 120
527+
start_worker_interval: 2
528+
market_data_chunk_size: 1
529+
timezone: Europe/Paris
530+
531+
exchanges:
532+
kraken:
533+
required:
534+
enabled: true
535+
all_pairs:
536+
- USD
537+
538+
indicators:
539+
rsi:
540+
- enabled: true
541+
alert_enabled: true
542+
alert_frequency: always
543+
signal:
544+
- rsi
545+
hot: 30
546+
cold: 70
547+
candle_period: 1h
548+
period_count: 14
549+
- enabled: true
550+
alert_enabled: true
551+
alert_frequency: always
552+
signal:
553+
- rsi
554+
hot: 40
555+
cold: 60
556+
candle_period: 1d
557+
period_count: 14
558+
bollinger:
559+
- enabled: true
560+
candle_period: 1h
561+
alert_enabled: true
562+
alert_frequency: always
563+
period_count: 25
564+
std_dev: 2.5
565+
signal:
566+
- low_band
567+
- close
568+
- up_band
569+
mute_cold: false
570+
- enabled: true
571+
candle_period: 1d
572+
alert_enabled: true
573+
alert_frequency: always
574+
period_count: 25
575+
std_dev: 2.5
576+
signal:
577+
- low_band
578+
- close
579+
- up_band
580+
mute_cold: false
581+
aroon_oscillator:
582+
- enabled: true
583+
alert_enabled: true
584+
alert_frequency: always
585+
sma_vol_period: 50
586+
period_count: 14
587+
signal:
588+
- aroon
589+
candle_period: 1h
590+
591+
conditionals:
592+
- label: "Signal to buy"
593+
hot:
594+
- rsi: 0
595+
- rsi: 1
596+
cold:
597+
- bollinger: 0
598+
- label: "Signal to buy"
599+
hot:
600+
- rsi: 1
601+
- label: "Signal to sell"
602+
cold:
603+
- rsi: 1
604+
- rsi: 0
605+
hot:
606+
- aroon_oscillator: 0
607+
608+
notifiers:
609+
telegram:
610+
required:
611+
token: X
612+
chat_id: Y
613+
optional:
614+
parse_mode: html
615+
template: "[{{market}}] {{indicator}} {{status}} {{values}} {{ '\n' -}}"
616+
```
617+
618+
## Template value available
619+
- values
620+
- indicator
621+
- exchange
622+
- market
623+
- base_currency
624+
- quote_currency
625+
- status
626+
627+
The `status` will be the string set in `label`.
628+
629+
# 9) Examples
513630
Putting it all together an example config.yml might look like the config below if you want to use the default settings with bittrex
514631

515632
```yml

0 commit comments

Comments
 (0)