def send_alert(data): if config.send_telegram_alerts: tg_bot = Bot(token=config.tg_token) try: tg_bot.sendMessage(data['telegram'], data['msg'].encode('latin-1', 'backslashreplace').decode('unicode_escape'), parse_mode='MARKDOWN') except KeyError: tg_bot.sendMessage(config.channel, data['msg'].encode('latin-1', 'backslashreplace').decode('unicode_escape'), parse_mode='MARKDOWN') except Exception as e: print('[X] Telegram Error:\n>', e) if config.send_discord_alerts: try: webhook = DiscordWebhook(url="https://discord.com/api/webhooks/" + data['discord']) embed = DiscordEmbed(title=data['msg']) webhook.add_embed(embed) response = webhook.execute() except KeyError: webhook = DiscordWebhook(url="https://discord.com/api/webhooks/" + config.discord_webhook) embed = DiscordEmbed(title=data['msg']) webhook.add_embed(embed) response = webhook.execute() except Exception as e: print('[X] Discord Error:\n>', e) if config.send_slack_alerts: try: slack = Slack(url='https://hooks.slack.com/services/' + data['slack']) slack.post(text=data['msg']) except KeyError: slack = Slack(url='https://hooks.slack.com/services/' + config.slack_webhook) slack.post(text=data['msg']) except Exception as e: print('[X] Slack Error:\n>', e) if config.send_twitter_alerts: tw_auth = tweepy.OAuthHandler(config.tw_ckey, config.tw_csecret) tw_auth.set_access_token(config.tw_atoken, config.tw_asecret) tw_api = tweepy.API(tw_auth) try: tw_api.update_status(status=data['msg'].replace('*', '').replace('_', '').replace('`', '')) except Exception as e: print('[X] Twitter Error:\n>', e) if config.send_email_alerts: try: email_msg = MIMEText(data['msg'].replace('*', '').replace('_', '').replace('`', '')) email_msg['Subject'] = config.email_subject email_msg['From'] = config.email_sender email_msg['To'] = config.email_sender context = ssl.create_default_context() with smtplib.SMTP_SSL(config.email_host, config.email_port, context=context) as server: server.login(config.email_user, config.email_password) server.sendmail(config.email_sender, config.email_receivers, email_msg.as_string()) server.quit() except Exception as e: print('[X] Email Error:\n>', e)
def send_slack_notification(channel, channel_url, game, live_started_at, thumbnail_url, title, viewers): slack = Slack(url=config['webhook-url'].format(os.getenv('SLACK_API_KEY'))) slack.post( text='{} is live: {}'.format(channel, game), blocks=[{ 'type': 'section', 'text': { 'type': 'mrkdwn', 'text': '*{} is live: {}*'.format(channel, game) } }, { 'type': 'section', 'text': { 'type': 'mrkdwn', 'text': '<{url}|{channel}: {title}>\n{channel} now streaming "{game} - {title}" with {viewers} viewers ({time})' .format(url=channel_url, channel=channel, title=title, viewers=viewers, game=game, time=utc_to_local(live_started_at).strftime( '%d %b %Y at %H:%M')) }, 'accessory': { 'type': 'image', 'image_url': thumbnail_url, 'alt_text': 'Twitch thumbnail' } }])
def backup_not_found(): ls = subprocess.Popen(['ls', '-lt', path], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) head = subprocess.Popen(['head', '-11'], stdin=ls.stdout, stdout=subprocess.PIPE, text=True) tail = subprocess.Popen(['tail', '-10'], stdin=head.stdout, stdout=subprocess.PIPE, text=True) res = tail.communicate() message = """ Pi-Hole backup FAILED! Backup file not present. The 10 most recent files are thus: ```{}``` manual investigation is necessary. """.format(res[0]) slack = Slack(url=webhook) slack.post(text=message)
def playbook_on_stats(self, stats): if stats.failures: message = "Failure" color = 'danger' else: message = "Success" color = 'good' execution_time = time.time()-self.start_time slack = Slack(url=webhook_url) message = "{}@{}\nPlaybook: {}".format(self.user, self.hostname, self.playbook_name) fields = [{ "title": "Start time", "value": "{}".format(self.start_datetime), "short": True },{ "title": "Execution time", "value": "{:10.2f}s".format(execution_time), "short": True }] for cat in ("ok","changed","unreachable","failures","skipped","rescued","ignored"): results = getattr(stats, cat, {}) found = False if results: for key in getattr(stats, cat, {}).keys(): found = True fields.append( { "title": cat.capitalize(), "value": "{}".format(getattr(stats, cat, {}).get(key)), "short": True } ) if not found: fields.append( { "title": cat.capitalize(), "value": "0", "short": True } ) self._display.warning(stats.__dict__) payload = [{ "fallback": "Ansible Play Recap for {}".format(self.playbook_name), "color": str(color), "title": "Ansible Play Recap : {}".format(self.playbook_name), "text": str(message), "fields": fields }] slack.post(attachments=payload)
def sendMessage(message): slack = Slack(url='https://hooks.slack.com/services/###') # Slack webhook slack.post( attachments=[{ "color": "#ff0000", #"fallback": "Plan a vacation", "author_name": "", "title": "Speedtest", "text": message }] )
def main(): quotes = download_quotes(target_url) quotes = remove_markdown_heading_spaces(quotes) quote = pick_quote_for_today(quotes) print("Quote of the day") print(quote) if slack_webhook_url is not None: slack = Slack(url=slack_webhook_url) slack.post(text=quote)
def handle(event, context): # Make sure to create the secrets below webhook_url = fetch_secret("slack-webhook-url") stripe.api_key = fetch_secret("stripe-secret-key") webhook_secret = fetch_secret("webhook-secret") payload = event.body received_sig = event.headers.get("Stripe-Signature", None) try: event = stripe.Webhook.construct_event( payload, received_sig, webhook_secret ) except ValueError: print("Error while decoding event!") return { "body": "Bad payload", "statusCode": 400 } except stripe.error.SignatureVerificationError: print("Invalid signature!") return { "body": "Bad signature", "statusCode": 400 } # Fail for all other event types if event.type != "charge.succeeded": return { "body":"Unsupported event type", "statusCode": 422 } amount = numbers.format_currency( event.data.object.amount / 100, event.data.object.currency.upper(), locale='en' ) try: slack = Slack(url=webhook_url) slack.post(text=f"You have a received a new payment of {amount} :moneybag: :tada:") except: print("An error occured when trying to send slack message.") return { "body": "Could not send slack message", "statusCode": 500 } return { "body": "Notification was sent successfully to Slack", "statusCode": 200 }
def sendSlack(self): self.set_globalSettings(self.defaultSettings, "SlackWebHook") if len(self.globalSettings.get("SlackWebHook")) > 0: lis = self.get_list(self.globalSettings.get("SlackWebHook")) try: for hooks in lis: text = self.subject+"\n\n"+self.body slack = Slack(url=hooks) slack.post(text=text) logger.info(f"Slack sent to: {hooks}") except Exception as ex: logger.info(ex)
def crawling(): with open('config.json', 'r') as f: config = json.load(f) time.sleep(random.choice(r_times)) html = requests.get( web_url, headers={ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36' }).text soup = BeautifulSoup(html, 'html.parser') result_text = soup.text[6:-2] a = json.loads(result_text) postList = a['result']['popularPostBlockInfoList'][0]['postList'] now = datetime.datetime.now() month = int(now.strftime('%m')) nowDate = now.strftime( (str(month) + '월%d일' ).encode('unicode-escape').decode()).encode().decode('unicode-escape') for post in postList: if nowDate in post['titleWithInspectMessage']: img_src = post['thumbnailList'][0]['encodedThumbnailUrl'] slack = Slack(url=config['WEBHOOK_URL']) today_menu = "쉐프스케치, " + "[" + nowDate + "] 오늘의 메뉴" slack.post( text=today_menu, channel="#오늘의메뉴", attachments=[{ # "fallback": href, # "pretext": href, "color": "#00FFFF", "author_name": "", "title": today_menu, # "title_link": href, "image_url": img_src, "thumb_url": img_src, # "actions": [ # { # "name": "action", # "type": "button", # "text": "Complete this task", # "style": "", # "value": "complete" # }, # ] }])
def send(self): webhook_url = self.get_destination() payload = self.get_messages() slack = Slack(url=webhook_url) if 'text' not in payload.keys(): expression = payload messages = 'text key not exist on payload input' raise InputExpression(expression, messages) elif 'attachments' not in payload.keys(): slack.post(text=payload['text']) else: slack.post(text=payload['text'], attachments=payload['attachments'])
def success(message): slack = Slack(url=SLACK_WEBHOOK) slack.post(text=KST.strftime('%Y.%m.%d') + " 자가진단 결과: ✅ 성공", attachments=[{ "color": "#00b894", "author_name": "✅ " + KST.strftime('%Y.%m.%d'), "title": message, "text": "처리 기준 (KST): " + KST.strftime('%Y-%m-%d %H:%M:%S') }])
def failed(message): slack = Slack(url=SLACK_WEBHOOK) slack.post(text=KST.strftime('%Y.%m.%d') + " 자가진단 결과: ⛔️ 실패", attachments=[{ "color": "#d63031", "author_name": "⛔ " + KST.strftime('%Y.%m.%d'), "title": message, "text": "처리 기준 (KST): " + KST.strftime('%Y-%m-%d %H:%M:%S') }])
def main(req: func.HttpRequest) -> func.HttpResponse: logging.info('Python HTTP trigger function processed a request.') slack_url = os.getenv('SLACK_URL') slack = Slack(url=(slack_url)) req_body = req.get_json() logging.info(format(req_body)) slack.post(text=f"system: {req_body['systemName']} \n" f"system model: {req_body['systemModel']} \n" f"current score: {req_body['currentScore']} \n" f"timestamp: {req_body['timestampIso8601']} \n" "description: {req_body['description']} \n" "resolution: {req_body['resolution']}") # slack.post(text=f"system: {req_body}") logging.info('Successfully posted to Slack.') return func.HttpResponse(format(req_body))
def publish_cluster(): slack= Slack(url='https://hooks.slack.com/services/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') credentials = key_read(file_loc) # Code for Redshift Task try: session = boto3.Session( aws_access_key_id=credentials['access_key'] , aws_secret_access_key=credentials['secret_key'], aws_session_token=credentials['token'] ) ddb = session.client('redshift', 'us-east-1') cluster_list = ddb.describe_clusters() slack.post(text="Describe Clusters Detail Successful") except: slack.post("Invalid Credentials or EC2 Role")
def send_slack_webhook_message(match, videogoal, videogoal_mirror, event_filter): try: webhooks = Webhook.objects.filter( destination__exact=Webhook.WebhookDestinations.Slack, event_type=event_filter) print( f"WEBHOOK - Checking {str(event_filter)} - {str(len(webhooks))} SLACK WEBHOOKS", flush=True) for wh in webhooks: to_send = check_conditions(match, wh) and \ check_link_regex(wh, videogoal, videogoal_mirror, event_filter) and \ check_author(wh, videogoal, videogoal_mirror, event_filter) if not to_send: continue message = format_event_message(match, videogoal, videogoal_mirror, wh.message) try: slack = Slack(url=wh.webhook_url) response = slack.post(text=message) print(response, flush=True) except Exception as ex: print("Error sending webhook single message: " + str(ex), flush=True) except Exception as ex: print("Error sending webhook messages: " + str(ex), flush=True)
def nfs_not_mounted(): # print('NFS not mounted') cmd = ['df', '-h'] res = subprocess.run(cmd, capture_output=True, text=True) message = """ Pi-Hole backup FAILED! Backup directory not present. the following is the output of `df -h`: ```{}``` manual investigation is necessary. """.format(res.stdout) slack = Slack(url=webhook) slack.post(text=message)
def sendSlackNotify(event: eventData.ContEvent, data: dataData.ContData, config: configInit.Config): slackClient = Slack(url=config.slackUrl) imageIcon = logoIcons.getLogoUrl(event.image) mainInfo = f"_Docker Container Crashed Detected_\n\n:pirate_flag: *Container Name*\n `{event.name.capitalize()}`\n\n" introMsg = sectionWithImage(mainInfo, imageIcon) errorMsg = newSection(f"{data.errorMsg}\n") tagsField = None if config.tags is not None: tags = "" for t in config.tags: tags = tags + f"`{t}`; " tagsField = f":flags: *Tags*\n{tags}\n\n" tagsField = newSection(tagsField) restartPolicy = None if data.restartPolicy is not None: restartPolicy = f":repeat: *Restart Policy*: `{data.restartPolicy}`\n:repeat_one: *Max Count Restarts Notify*: `{config.restartPolicyCountNotify}`\n" restartPolicy = restartPolicy + f":arrows_counterclockwise: *Current Restart Count*: `{data.restartCount}`\n\n" restartPolicy = newSection(restartPolicy) image = f":frame_with_picture: *Image*\n`{event.image}`\n\n" image = newSection(image) exitCode = f":small_orange_diamond: *Exit Code*\n `{data.exitCode}`\n\n" exitCode = newSection(exitCode) oomKilled = f":anger: OOMKilled\n`{data.oomKilled}`\n\n" oomKilled = newSection(oomKilled) allFields = [introMsg, errorMsg, divider(), tagsField, restartPolicy, image, exitCode, oomKilled] filteredFields = [i for i in allFields if i] try: slackClient.post(blocks=filteredFields) except Exception as e: print(f"ERROR while sending message to Slack. Please check if the webhook URL is valid - now exiting! {e}") sys.exit(0)
def post(self): # Get name and email to send Slack logging.error("Send Slack Root") json_input = request.get_json() user_name_raw = json_input['user_name'] logging.error("raw : " + user_name_raw) user_email_raw = json_input['user_email'] logging.error("raw : " + user_email_raw) slack = Slack( url=f'https://hooks.slack.com/services/{config.slack_key}') slack.post( text= f"User : {user_name_raw} , email : {user_email_raw} have requested a demo" ) # return OK return "OK"
async def scale_up(request): global TOKEN global RANCHER_VM_MAX #authentication of requester to autoscaler if request.match_dict['token'] != TOKEN: print(f"token '{request.match_dict['token']}' not valid\n") return request.Response(text='ok') #authentication with Rancher pool = await get_nodepool() # check if we have uncordoned a node uncordoned_node, message = await try_uncordon_node_of_nodepool(pool['links']['nodes']) print(f"{message}") slack = Slack(url=SLACK_URL) if uncordoned_node: print(f"Not scaling up, Waiting for next message...\n") slack.post(text="Autoscaler message: "+message+ "\nNot scaling up, Waiting for next message...") return request.Response(text='ok') old = pool['quantity'] pool['quantity'] = pool['quantity'] + 1 # limit maximum VMs if RANCHER_VM_MAX + 1 <= pool['quantity']: print(f"Not scaling up, at maximum number of nodes\n") slack.post(text="Autoscaler message: "+message+ "\nNot scaling up, at maximum number of nodes") return request.Response(text='ok') slack.post(text="Autoscaler message: "+message) print(f"scale up {old} --> {pool['quantity']}") await set_nodepool(pool) return request.Response(text='ok')
async def scale_down(request): #authentication of requester to autoscaler global TOKEN if request.match_dict['token'] != TOKEN: print(f"token '{request.match_dict['token']}' not valid\n") return request.Response(text='ok') #authentication with Rancher pool = await get_nodepool() #setup slack webhook slack = Slack(url=SLACK_URL) #if we have reached the minimum number of nodes possible, end request if pool['quantity'] <= RANCHER_VM_MIN: print(f'quantity <= {RANCHER_VM_MIN}\n') slack.post(text="Autoscaler message: Not scaling down, quantity <= "+str(RANCHER_VM_MIN)) return request.Response(text='ok') # check if we have Cordoned node cordoned_node, message = await try_cordon_last_node_of_nodepool(pool['links']['nodes'], pool['hostnamePrefix']) print(f"{message}") if cordoned_node: print(f"Not scaling down, cordoning node instead. Waiting for next message...\n") slack.post(text="Autoscaler message: "+message+ "\nNot scaling down, Waiting for next message...") return request.Response(text='ok') #if we have reached here, scale down the node pool old = pool['quantity'] pool['quantity'] = pool['quantity'] - 1 print(f"scale down {old} --> {pool['quantity']}") slack.post(text="Autoscaler message: "+message+ "\nscale down "+str(old)+" --> "+str(pool['quantity'])) await set_nodepool(pool) return request.Response(text='ok')
def backup_found(): ls = subprocess.Popen(['ls', '-lt', path], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) head = subprocess.Popen(['head', '-2'], stdin=ls.stdout, stdout=subprocess.PIPE, text=True) tail = subprocess.Popen(['tail', '-1'], stdin=head.stdout, stdout=subprocess.PIPE, text=True) res = tail.communicate() message = """ Pi-Hole backup SUCCEEDED! Backup file created. The most recent file is: ```{}``` Qapla'! """.format(res[0]) slack = Slack(url=webhook) slack.post(text=message)
def lambda_handler(event, context): print('add current working directory to PATH') slack = Slack(url=os.environ['SLACK_WEBHOOK_URL']) os.environ['PATH'] = os.environ['PATH'] + ':' + os.path.dirname( os.path.abspath(__file__)) + ':' + os.path.join( os.path.dirname(os.path.abspath(__file__)), 'bin') try: mp3file_name = download() upload_to_s3(mp3file_name, os.environ['UPLOAD_GOOGLE_DRIVE_DIRECTORY']) upload_to_google_drive(mp3file_name, os.environ['UPLOAD_GOOGLE_DRIVE_DIRECTORY']) upload_to_youtube_music(mp3file_name) slack.post(text='[insideout] :tada: done recording insideout') except Exception as e: slack.post(text='[insideout] :red_circle: failed to record insideout') raise e # run radirec return { 'isBase64Encoded': False, 'statusCode': 200, 'headers': {}, 'body': '{"message": "Hello from AWS Lambda"}' }
def send_slack_webhook_message(match, videogoal, videogoal_mirror, event_filter): try: webhooks = Webhook.objects.filter( destination__exact=Webhook.WebhookDestinations.Slack, event_type=event_filter) for wh in webhooks: to_send = check_conditions(match, wh) and \ check_link_regex(wh, videogoal, videogoal_mirror, event_filter) and \ check_author(wh, videogoal, videogoal_mirror, event_filter) if not to_send: return message = format_event_message(match, videogoal, videogoal_mirror, wh.message) try: slack = Slack(url=wh.webhook_url) response = slack.post(text=message) print(response) except Exception as ex: print("Error sending webhook single message: " + str(ex)) except Exception as ex: print("Error sending webhook messages: " + str(ex))
def send_message(sender, instance, **kwargs): if kwargs['action'] != 'post_add': return result = '' for wh in instance.webhooks.all(): if wh.destination == Webhook.WebhookDestinations.Discord: try: webhook = DiscordWebhook(url=wh.webhook_url, content=instance.message) response = webhook.execute() result += wh.title + "\n" + str(response.content) + "\n\n" print(response.content, flush=True) except Exception as ex: print("Error sending webhook single message: " + str(ex), flush=True) result += wh.title + "\n" + str(ex) + "\n\n" elif wh.destination == Webhook.WebhookDestinations.Slack: try: slack = Slack(url=wh.webhook_url) response = slack.post(text=instance.message) print(response, flush=True) result += wh.title + "\n" + str(response) + "\n\n" except Exception as ex: print("Error sending webhook single message: " + str(ex), flush=True) result += wh.title + "\n" + str(ex) + "\n\n" CustomMessage.objects.filter(id=instance.id).update(result=result)
def notify_slack(post): slack = Slack(url=os.environ.get('SLACK_URL')) slack.post(text=post)
#draw.text((x, top+25), str(Disk), font=font, fill=255) # Display image. disp.image(image) disp.display() #time.sleep(.1) # if it is later in the day and temperature outside is less than # inside temperature open the window # check operating window - this sets time constraints if (outTemp >= inTemp): if (notFlagged is True): notFlagged = False try: slack.post(text=str(weather['time']) + " " + tempStr + " Outside temp greater than inside") except Exception as e: print("Error on slack post") else: if (outTemp < inTemp - 1.0): # stop the ping pong notFlagged = True # we need the outside temperature to be pleasant and for it # to be a degree or two lower that the inside temperature # and for the inside temperature not to drop below 22 # # - add some hysteresis so it doesn't go up and down! - add timer # - have been agreessive on the 'differences' as the outside read # is a bit high timeDelay = 30 * 60 # 30mins
def send_alert(data): msg = data["msg"].encode("latin-1", "backslashreplace").decode("unicode_escape") if config.send_telegram_alerts: tg_bot = Bot(token=config.tg_token) try: tg_bot.sendMessage( data["telegram"], msg, parse_mode="MARKDOWN", ) except KeyError: tg_bot.sendMessage( config.channel, msg, parse_mode="MARKDOWN", ) except Exception as e: print("[X] Telegram Error:\n>", e) if config.send_discord_alerts: try: webhook = DiscordWebhook(url="https://discord.com/api/webhooks/" + data["discord"]) embed = DiscordEmbed(title=msg) webhook.add_embed(embed) webhook.execute() except KeyError: webhook = DiscordWebhook(url="https://discord.com/api/webhooks/" + config.discord_webhook) embed = DiscordEmbed(title=msg) webhook.add_embed(embed) webhook.execute() except Exception as e: print("[X] Discord Error:\n>", e) if config.send_slack_alerts: try: slack = Slack(url="https://hooks.slack.com/services/" + data["slack"]) slack.post(text=msg) except KeyError: slack = Slack(url="https://hooks.slack.com/services/" + config.slack_webhook) slack.post(text=msg) except Exception as e: print("[X] Slack Error:\n>", e) if config.send_twitter_alerts: tw_auth = tweepy.OAuthHandler(config.tw_ckey, config.tw_csecret) tw_auth.set_access_token(config.tw_atoken, config.tw_asecret) tw_api = tweepy.API(tw_auth) try: tw_api.update_status( status=msg.replace("*", "").replace("_", "").replace("`", "")) except Exception as e: print("[X] Twitter Error:\n>", e) if config.send_email_alerts: try: email_msg = MIMEText( msg.replace("*", "").replace("_", "").replace("`", "")) email_msg["Subject"] = config.email_subject email_msg["From"] = config.email_sender email_msg["To"] = config.email_sender context = ssl.create_default_context() with smtplib.SMTP_SSL(config.email_host, config.email_port, context=context) as server: server.login(config.email_user, config.email_password) server.sendmail(config.email_sender, config.email_receivers, email_msg.as_string()) server.quit() except Exception as e: print("[X] Email Error:\n>", e)
def send_to_slack(title, url, chapter): webhook_url = WEBHOOK_URL # 公開するな! slack = Slack(url=webhook_url) message = f'【更新】: {title} {chapter} \n{url}' slack.post(text=message)
class Bot(object): WINTER_TIME = 21 SUMMER_TIME = 20 def __init__( self, *, account_id: str, access_token: str, environment: str = "practice", instrument: str = "EUR_USD", granularity: str = "D", trading_time: int = SUMMER_TIME, slack_webhook_url: str = "", discord_webhook_url: str = "", line_notify_token: str = "", ) -> None: self.BUY = 1 self.SELL = -1 self.EXIT = False self.ENTRY = True self.trading_time = trading_time self.account_id = account_id self.headers = { "Content-Type": "application/json", "Authorization": "Bearer {}".format(access_token), } if environment == "practice": self.base_url = "https://api-fxpractice.oanda.com" else: self.base_url = "https://api-fxtrade.oanda.com" self.sched = BlockingScheduler() self.instrument = instrument self.granularity = granularity if len(granularity) > 1: if granularity[0] == "S": self.sched.add_job(self._job, "cron", second="*/" + granularity[1:]) elif granularity[0] == "M": self.sched.add_job(self._job, "cron", minute="*/" + granularity[1:]) elif granularity[0] == "H": self.sched.add_job(self._job, "cron", hour="*/" + granularity[1:]) else: if granularity == "D": self.sched.add_job(self._job, "cron", day="*") elif granularity == "W": self.sched.add_job(self._job, "cron", week="*") elif granularity == "M": self.sched.add_job(self._job, "cron", month="*") if slack_webhook_url == "": self.slack = None else: self.slack = Slack(url=slack_webhook_url) if line_notify_token == "": self.line = None else: self.line = Line(token=line_notify_token) if discord_webhook_url == "": self.discord = None else: self.discord = Discord(url=discord_webhook_url) formatter = logging.Formatter( "%(asctime)s - %(funcName)s - %(levelname)s - %(message)s" ) handler = logging.StreamHandler() handler.setLevel(logging.INFO) handler.setFormatter(formatter) self.log = logging.getLogger(__name__) self.log.setLevel(logging.INFO) self.log.addHandler(handler) if "JPY" in self.instrument: self.point = 0.01 else: self.point = 0.0001 self.units = 10000 # currency unit self.take_profit = 0 self.stop_loss = 0 self.buy_entry = ( self.buy_exit ) = self.sell_entry = self.sell_exit = pd.DataFrame() def _candles( self, *, from_date: str = "", to_date: str = "", count: str = "5000" ) -> pd.DataFrame: url = "{}/v3/instruments/{}/candles".format(self.base_url, self.instrument) params = {"granularity": self.granularity, "count": count} if from_date != "": _dt = dateutil.parser.parse(from_date) params["from"] = str( datetime.datetime( _dt.year, _dt.month, _dt.day, tzinfo=datetime.timezone.utc ).date() ) if to_date != "": _dt = dateutil.parser.parse(to_date) params["to"] = str( datetime.datetime( _dt.year, _dt.month, _dt.day, tzinfo=datetime.timezone.utc ).date() ) data = [] if "from" in params and "to" in params: _from = params["from"] _to = params["to"] del params["to"] while _to > _from: time.sleep(0.5) params["from"] = _from res = requests.get(url, headers=self.headers, params=params) if res.status_code != 200: self._error( "status_code {} - {}".format(res.status_code, res.json()) ) for r in res.json()["candles"]: data.append( [ pd.to_datetime(r["time"]), float(r["mid"]["o"]), float(r["mid"]["h"]), float(r["mid"]["l"]), float(r["mid"]["c"]), float(r["volume"]), ] ) _dt = pd.to_datetime(res.json()["candles"][-1]["time"]) _from = str(datetime.date(_dt.year, _dt.month, _dt.day)) else: res = requests.get(url, headers=self.headers, params=params) if res.status_code != 200: self._error("status_code {} - {}".format(res.status_code, res.json())) for r in res.json()["candles"]: data.append( [ pd.to_datetime(r["time"]), float(r["mid"]["o"]), float(r["mid"]["h"]), float(r["mid"]["l"]), float(r["mid"]["c"]), float(r["volume"]), ] ) self.df = ( pd.DataFrame(data, columns=["T", "O", "H", "L", "C", "V"]) .set_index("T") .drop_duplicates() ) return self.df def __accounts(self) -> requests.models.Response: url = "{}/v3/accounts/{}".format(self.base_url, self.account_id) res = requests.get(url, headers=self.headers) if res.status_code != 200: self._error("status_code {} - {}".format(res.status_code, res.json())) return res def _account(self) -> Tuple[bool, bool]: buy_position = False sell_position = False for pos in self.__accounts().json()["account"]["positions"]: if pos["instrument"] == self.instrument: if pos["long"]["units"] != "0": buy_position = True if pos["short"]["units"] != "0": sell_position = True return buy_position, sell_position def __order(self, data: Any) -> requests.models.Response: url = "{}/v3/accounts/{}/orders".format(self.base_url, self.account_id) res = requests.post(url, headers=self.headers, data=json.dumps(data)) if res.status_code != 201: self._error("status_code {} - {}".format(res.status_code, res.json())) return res def _order(self, sign: int, entry: bool = False) -> None: order = {} order["instrument"] = self.instrument order["units"] = str(self.units * sign) order["type"] = "MARKET" order["positionFill"] = "DEFAULT" res = self.__order({"order": order}) order_id = res.json()["orderFillTransaction"]["id"] price = float(res.json()["orderFillTransaction"]["price"]) if self.stop_loss != 0 and entry: stop_loss = {} stop_loss["timeInForce"] = "GTC" stop_loss["price"] = str( round(price + (self.stop_loss * self.point * -sign), 3) ) stop_loss["type"] = "STOP_LOSS" stop_loss["tradeID"] = order_id self.__order({"order": stop_loss}) if self.take_profit != 0 and entry: take_profit = {} take_profit["timeInForce"] = "GTC" take_profit["price"] = str( round(price + (self.take_profit * self.point * sign), 3) ) take_profit["type"] = "TAKE_PROFIT" take_profit["tradeID"] = order_id self.__order({"order": take_profit}) def _is_close(self) -> bool: utcnow = datetime.datetime.utcnow() hour = utcnow.hour weekday = utcnow.weekday() if ( (4 == weekday and self.trading_time < hour) or 5 == weekday or (6 == weekday and self.trading_time >= hour) ): return True return False def _job(self) -> None: if self._is_close(): return None self._candles(count="500") self.strategy() buy_position, sell_position = self._account() buy_entry = self.buy_entry[-1] sell_entry = self.sell_entry[-1] buy_exit = self.buy_exit[-1] sell_exit = self.sell_exit[-1] # buy entry if buy_entry and not buy_position: if sell_position: self._order(self.BUY) self._order(self.BUY, self.ENTRY) return None # sell entry if sell_entry and not sell_position: if buy_position: self._order(self.SELL) self._order(self.SELL, self.ENTRY) return None # buy exit if buy_exit and buy_position: self._order(self.SELL) # sell exit if sell_exit and sell_position: self._order(self.BUY) def _error(self, message: Any = {}) -> None: self.log.error(message) if self.slack is not None: self.slack.post(text=message) if self.line is not None: self.line.post(message=message) if self.discord is not None: self.discord.post(content=message) def __transactions(self, params: Any = {}) -> requests.models.Response: url = "{}/v3/accounts/{}/transactions".format(self.base_url, self.account_id) res = requests.get(url, headers=self.headers, params=params) if res.status_code != 200: self._error("status_code {} - {}".format(res.status_code, res.json())) return res def __transactions_sinceid(self, params: Any = {}) -> requests.models.Response: url = "{}/v3/accounts/{}/transactions/sinceid".format( self.base_url, self.account_id ) res = requests.get(url, headers=self.headers, params=params) if res.status_code != 200: self._error("status_code {} - {}".format(res.status_code, res.json())) return res def report(self, *, days: int = -1, filename: str = "",) -> None: tran = self.__transactions( { "from": ( datetime.datetime.utcnow().date() + datetime.timedelta(days=days) ), "type": "ORDER_FILL", } ).json() id = parse.parse_qs(parse.urlparse(tran["pages"][0]).query)["from"] data = [] for t in self.__transactions_sinceid({"id": id, "type": "ORDER_FILL"}).json()[ "transactions" ]: if float(t["pl"]) == 0.0: continue data.append( [ pd.to_datetime(t["time"]), t["id"], float(t["pl"]), round(float(t["pl"]), 2), float(t["price"]), float(t["accountBalance"]), ] ) df = pd.DataFrame( data, columns=["time", "id", "pl", "rr", "price", "accountBalance"] ).set_index("time") s = pd.Series(dtype="object") s.loc["total profit"] = round(df["pl"].sum(), 3) s.loc["total trades"] = len(df["pl"]) s.loc["win rate"] = round(len(df[df["pl"] > 0]) / len(df["pl"]) * 100, 3) s.loc["profit factor"] = round( df[df["pl"] > 0]["pl"].sum() / df[df["pl"] <= 0]["pl"].sum(), 3 ) s.loc["maximum drawdown"] = round( (df["accountBalance"].cummax() - df["accountBalance"]).max(), 3 ) s.loc["recovery factor"] = round( df["pl"].sum() / (df["accountBalance"].cummax() - df["accountBalance"]).max(), 3, ) s.loc["riskreward ratio"] = round( (df[df["pl"] > 0]["pl"].sum() / len(df[df["pl"] > 0])) / (df[df["pl"] <= 0]["pl"].sum() / len(df[df["pl"] <= 0])), 3, ) s.loc["sharpe ratio"] = round(df["rr"].mean() / df["rr"].std(), 3) s.loc["average return"] = round(df["rr"].mean(), 3) print(s) fig = plt.figure() fig.subplots_adjust( wspace=0.2, hspace=0.7, left=0.095, right=0.95, bottom=0.095, top=0.95 ) ax1 = fig.add_subplot(3, 1, 1) ax1.plot(df["price"], label="price") ax1.xaxis.set_major_formatter(mdates.DateFormatter("%m-%d\n%H:%M")) ax1.legend() ax2 = fig.add_subplot(3, 1, 2) ax2.plot(df["accountBalance"], label="accountBalance") ax2.xaxis.set_major_formatter(mdates.DateFormatter("%m-%d\n%H:%M")) ax2.legend() ax3 = fig.add_subplot(3, 1, 3) ax3.hist(df["rr"], 50, rwidth=0.9) ax3.axvline( df["rr"].mean(), color="orange", label="average return", ) ax3.legend() if filename == "": plt.show() else: plt.savefig(filename) def strategy(self) -> None: pass def backtest( self, *, from_date: str = "", to_date: str = "", filename: str = "" ) -> None: csv = "{}-{}-{}-{}.csv".format( self.instrument, self.granularity, from_date, to_date ) if os.path.exists(csv): self.df = pd.read_csv( csv, index_col=0, parse_dates=True, infer_datetime_format=True ) else: self._candles(from_date=from_date, to_date=to_date) if from_date != "" and to_date != "": self.df.to_csv(csv) self.strategy() o = self.df.O.values L = self.df.L.values h = self.df.H.values N = len(self.df) long_trade = np.zeros(N) short_trade = np.zeros(N) # buy entry buy_entry_s = np.hstack((False, self.buy_entry[:-1])) # shift long_trade[buy_entry_s] = o[buy_entry_s] # buy exit buy_exit_s = np.hstack((False, self.buy_exit[:-2], True)) # shift long_trade[buy_exit_s] = -o[buy_exit_s] # sell entry sell_entry_s = np.hstack((False, self.sell_entry[:-1])) # shift short_trade[sell_entry_s] = o[sell_entry_s] # sell exit sell_exit_s = np.hstack((False, self.sell_exit[:-2], True)) # shift short_trade[sell_exit_s] = -o[sell_exit_s] long_pl = pd.Series(np.zeros(N)) # profit/loss of buy position short_pl = pd.Series(np.zeros(N)) # profit/loss of sell position buy_price = sell_price = 0 long_rr = [] # long return rate short_rr = [] # short return rate stop_loss = take_profit = 0 for i in range(1, N): # buy entry if long_trade[i] > 0: if buy_price == 0: buy_price = long_trade[i] short_trade[i] = -buy_price # sell exit else: long_trade[i] = 0 # sell entry if short_trade[i] > 0: if sell_price == 0: sell_price = short_trade[i] long_trade[i] = -sell_price # buy exit else: short_trade[i] = 0 # buy exit if long_trade[i] < 0: if buy_price != 0: long_pl[i] = ( -(buy_price + long_trade[i]) * self.units ) # profit/loss fixed long_rr.append( round(long_pl[i] / buy_price * 100, 2) ) # long return rate buy_price = 0 else: long_trade[i] = 0 # sell exit if short_trade[i] < 0: if sell_price != 0: short_pl[i] = ( sell_price + short_trade[i] ) * self.units # profit/loss fixed short_rr.append( round(short_pl[i] / sell_price * 100, 2) ) # short return rate sell_price = 0 else: short_trade[i] = 0 # close buy position with stop loss if buy_price != 0 and self.stop_loss > 0: stop_price = buy_price - self.stop_loss * self.point if L[i] <= stop_price: long_trade[i] = -stop_price long_pl[i] = ( -(buy_price + long_trade[i]) * self.units ) # profit/loss fixed long_rr.append( round(long_pl[i] / buy_price * 100, 2) ) # long return rate buy_price = 0 stop_loss += 1 # close buy positon with take profit if buy_price != 0 and self.take_profit > 0: limit_price = buy_price + self.take_profit * self.point if h[i] >= limit_price: long_trade[i] = -limit_price long_pl[i] = ( -(buy_price + long_trade[i]) * self.units ) # profit/loss fixed long_rr.append( round(long_pl[i] / buy_price * 100, 2) ) # long return rate buy_price = 0 take_profit += 1 # close sell position with stop loss if sell_price != 0 and self.stop_loss > 0: stop_price = sell_price + self.stop_loss * self.point if h[i] >= stop_price: short_trade[i] = -stop_price short_pl[i] = ( sell_price + short_trade[i] ) * self.units # profit/loss fixed short_rr.append( round(short_pl[i] / sell_price * 100, 2) ) # short return rate sell_price = 0 stop_loss += 1 # close sell position with take profit if sell_price != 0 and self.take_profit > 0: limit_price = sell_price - self.take_profit * self.point if L[i] <= limit_price: short_trade[i] = -limit_price short_pl[i] = ( sell_price + short_trade[i] ) * self.units # profit/loss fixed short_rr.append( round(short_pl[i] / sell_price * 100, 2) ) # short return rate sell_price = 0 take_profit += 1 win_trades = np.count_nonzero(long_pl.clip(lower=0)) + np.count_nonzero( short_pl.clip(lower=0) ) lose_trades = np.count_nonzero(long_pl.clip(upper=0)) + np.count_nonzero( short_pl.clip(upper=0) ) trades = (np.count_nonzero(long_trade) // 2) + ( np.count_nonzero(short_trade) // 2 ) gross_profit = long_pl.clip(lower=0).sum() + short_pl.clip(lower=0).sum() gross_loss = long_pl.clip(upper=0).sum() + short_pl.clip(upper=0).sum() profit_pl = gross_profit + gross_loss self.equity = (long_pl + short_pl).cumsum() mdd = (self.equity.cummax() - self.equity).max() self.return_rate = pd.Series(short_rr + long_rr) s = pd.Series(dtype="object") s.loc["total profit"] = round(profit_pl, 3) s.loc["total trades"] = trades s.loc["win rate"] = round(win_trades / trades * 100, 3) s.loc["profit factor"] = round(-gross_profit / gross_loss, 3) s.loc["maximum drawdown"] = round(mdd, 3) s.loc["recovery factor"] = round(profit_pl / mdd, 3) s.loc["riskreward ratio"] = round( -(gross_profit / win_trades) / (gross_loss / lose_trades), 3 ) s.loc["sharpe ratio"] = round( self.return_rate.mean() / self.return_rate.std(), 3 ) s.loc["average return"] = round(self.return_rate.mean(), 3) s.loc["stop loss"] = stop_loss s.loc["take profit"] = take_profit print(s) fig = plt.figure() fig.subplots_adjust( wspace=0.2, hspace=0.5, left=0.095, right=0.95, bottom=0.095, top=0.95 ) ax1 = fig.add_subplot(3, 1, 1) ax1.plot(self.df.C, label="close") ax1.legend() ax2 = fig.add_subplot(3, 1, 2) ax2.plot(self.equity, label="equity") ax2.legend() ax3 = fig.add_subplot(3, 1, 3) ax3.hist(self.return_rate, 50, rwidth=0.9) ax3.axvline( sum(self.return_rate) / len(self.return_rate), color="orange", label="average return", ) ax3.legend() if filename == "": plt.show() else: plt.savefig(filename) def run(self) -> None: self.sched.start() def sma(self, *, period: int, price: str = "C") -> pd.DataFrame: return self.df[price].rolling(period).mean() def ema(self, *, period: int, price: str = "C") -> pd.DataFrame: return self.df[price].ewm(span=period).mean() def bbands( self, *, period: int = 20, band: int = 2, price: str = "C" ) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]: std = self.df[price].rolling(period).std() mean = self.df[price].rolling(period).mean() return mean + (std * band), mean, mean - (std * band) def macd( self, *, fast_period: int = 12, slow_period: int = 26, signal_period: int = 9, price: str = "C", ) -> Tuple[pd.DataFrame, pd.DataFrame]: macd = ( self.df[price].ewm(span=fast_period).mean() - self.df[price].ewm(span=slow_period).mean() ) signal = macd.ewm(span=signal_period).mean() return macd, signal def stoch( self, *, k_period: int = 5, d_period: int = 3 ) -> Tuple[pd.DataFrame, pd.DataFrame]: k = ( (self.df.C - self.df.L.rolling(k_period).min()) / (self.df.H.rolling(k_period).max() - self.df.L.rolling(k_period).min()) * 100 ) d = k.rolling(d_period).mean() return k, d def mom(self, *, period: int = 10, price: str = "C") -> pd.DataFrame: return self.df[price].diff(period) def rsi(self, *, period: int = 14, price: str = "C") -> pd.DataFrame: return 100 - 100 / ( 1 - self.df[price].diff().clip(lower=0).rolling(period).mean() / self.df[price].diff().clip(upper=0).rolling(period).mean() ) def ao(self, *, fast_period: int = 5, slow_period: int = 34) -> pd.DataFrame: return ((self.df.H + self.df.L) / 2).rolling(fast_period).mean() - ( (self.df.H + self.df.L) / 2 ).rolling(slow_period).mean()
#!/bin/python3 import os import sys from slack_webhook import Slack WEBHOOK = os.getenv('SLACK_WEBHOOK', None) if WEBHOOK is None: print("****** webhook is empty ******") else: # Send to Slack slack = Slack(url=WEBHOOK) slack.post(text="Hey there! I just made a slack webhook!")