From 3574ee7d59bab2e8c30827832974248039618393 Mon Sep 17 00:00:00 2001 From: Brett Taylor Date: Tue, 11 May 2021 18:30:25 -0400 Subject: [PATCH] initial commit of slack bot --- Projects/ProjectsSchema.json | 7 ++ .../Icons-SVG-Sources/nodes/slack-bot.svg | 33 +++++++ Projects/Superalgos/Icons/slack-bot.png | Bin 0 -> 8023 bytes .../Schemas/App-Schema/slack-bot.json | 41 +++++++++ .../Schemas/App-Schema/social-bots.json | 12 +++ .../Schemas/Docs-Nodes/slack-bot.json | 58 ++++++++++++ .../Schemas/Docs-Nodes/social-bots.json | 4 +- .../Trading-Bot/Announcements/SlackBot.js | 87 ++++++++++++++++++ .../Trading-Bot/Announcements/SocialBots.js | 10 +- .../UI/Function-Libraries/ActionSwitch.js | 5 + .../LearningSessionFunctions.js | 2 +- .../Function-Libraries/SocialBotsFunctions.js | 58 +++++++++++- .../TradingSessionFunctions.js | 2 +- 13 files changed, 311 insertions(+), 8 deletions(-) create mode 100644 Projects/Superalgos/Icons-SVG-Sources/nodes/slack-bot.svg create mode 100644 Projects/Superalgos/Icons/slack-bot.png create mode 100644 Projects/Superalgos/Schemas/App-Schema/slack-bot.json create mode 100644 Projects/Superalgos/Schemas/Docs-Nodes/slack-bot.json create mode 100644 Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/SlackBot.js diff --git a/Projects/ProjectsSchema.json b/Projects/ProjectsSchema.json index 2fbb81987..339cc1576 100644 --- a/Projects/ProjectsSchema.json +++ b/Projects/ProjectsSchema.json @@ -682,6 +682,13 @@ "fileName": "DiscordBot.js", "folderName": "Trading-Bot/Announcements" }, + { + "name": "Slack Bot", + "propertyName": "slackBot", + "functionName": "newSuperalgosBotModulesSlackBot", + "fileName": "SlackBot.js", + "folderName": "Trading-Bot/Announcements" + }, { "name": "Trading Process", "propertyName": "tradingProcess", diff --git a/Projects/Superalgos/Icons-SVG-Sources/nodes/slack-bot.svg b/Projects/Superalgos/Icons-SVG-Sources/nodes/slack-bot.svg new file mode 100644 index 000000000..c37dc5eb4 --- /dev/null +++ b/Projects/Superalgos/Icons-SVG-Sources/nodes/slack-bot.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Projects/Superalgos/Icons/slack-bot.png b/Projects/Superalgos/Icons/slack-bot.png new file mode 100644 index 0000000000000000000000000000000000000000..1422ddd500e6056f19cb43aebbd08c699f781e3c GIT binary patch literal 8023 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 a+2Xp~m>SC#-|ygmeS5llyH#!8&G>Joq6!QE literal 0 HcmV?d00001 diff --git a/Projects/Superalgos/Schemas/App-Schema/slack-bot.json b/Projects/Superalgos/Schemas/App-Schema/slack-bot.json new file mode 100644 index 000000000..d672e4b2d --- /dev/null +++ b/Projects/Superalgos/Schemas/App-Schema/slack-bot.json @@ -0,0 +1,41 @@ +{ + "type": "Slack Bot", + "editors": { + "config": true + }, + "menuItems": [ + { + "action": "Configure", + "actionFunction": "uiObject.configEditor.activate", + "label": "Configure", + "iconPathOn": "configuration", + "iconPathOff": "configuration" + }, + { + "action": "Send Slack Test Message", + "label": "Send Slack Test Message", + "iconPathOn": "test-entity", + "iconPathOff": "test-entity", + "actionFunction": "payload.executeAction" + }, + { + "action": "Delete UI Object", + "askConfirmation": true, + "confirmationLabel": "Confirm to Delete", + "label": "Delete", + "iconPathOn": "delete-entity", + "iconPathOff": "delete-entity", + "actionFunction": "payload.executeAction" + } + ], + "initialValues": { + "config": "{\n\"webhookURL\": \"https://hooks.slack.com/services/abc/abc/abc\"\n}" + }, + "addLeftIcons": true, + "level": 3, + "attachingRules": { + "compatibleTypes": "->Social Bots->" + }, + "childrenNodesProperties": [], + "propertyNameAtParent": "slackBots" +} diff --git a/Projects/Superalgos/Schemas/App-Schema/social-bots.json b/Projects/Superalgos/Schemas/App-Schema/social-bots.json index 8b1011846..1e08f0fc4 100644 --- a/Projects/Superalgos/Schemas/App-Schema/social-bots.json +++ b/Projects/Superalgos/Schemas/App-Schema/social-bots.json @@ -13,6 +13,12 @@ "relatedUiObject": "Discord Bot", "actionFunction": "payload.executeAction" }, + { + "action": "Add UI Object", + "label": "Add Slack Bot", + "relatedUiObject": "Slack Bot", + "actionFunction": "payload.executeAction" + }, { "action": "Delete UI Object", "askConfirmation": true, @@ -40,6 +46,12 @@ "type": "array", "childType": "Discord Bot", "autoAdd": true + }, + { + "name": "slackBots", + "type": "array", + "childType": "Slack Bot", + "autoAdd": true } ], "propertyNameAtParent": "socialBots" diff --git a/Projects/Superalgos/Schemas/Docs-Nodes/slack-bot.json b/Projects/Superalgos/Schemas/Docs-Nodes/slack-bot.json new file mode 100644 index 000000000..b745a1206 --- /dev/null +++ b/Projects/Superalgos/Schemas/Docs-Nodes/slack-bot.json @@ -0,0 +1,58 @@ +{ + "type": "Discord Bot", + "definition": { + "text": "The Discord Bot node is used for defining the configuration for a Discord Bot. This bot allows Superalgos to send announcements to a Discord Channel.", + "updated": 1619546769461 + }, + "paragraphs": [ + { + "style": "Text", + "text": "In order to use the Discord Bot, you will need to create a new Webhook Integration in Discord. The only configuration that is required within Superalgos is the webhookURL.", + "updated": 1619546875758 + }, + { + "style": "Text", + "text": "Parameters:" + }, + { + "style": "Text", + "text": "- webhookURL - required - obtained from Integrations > Webhooks in the channel settings." + }, + { + "style": "Text", + "text": "- format - optional - allows custom formatting of the message being sent into Discord." + }, + { + "style": "Text", + "text": "Recognized Format Variables:" + }, + { + "style": "Text", + "text": "- `%{EXCHANGE}` the exchange which is operating, i.e. Binance" + }, + { + "style": "Text", + "text": "- `%{MARKET}` the market which is operating. i.e. BTC/USDT" + }, + { + "style": "Text", + "text": "- `%{MESSAGE}` the text being sent" + }, + { + "style": "Text", + "text": "An example format is:" + }, + { + "style": "Javascript", + "text": "\"%{EXCHANGE} %{MARKET}: %{MESSAGE}\"" + }, + { + "style": "Text", + "text": "Which results in a final message in Discord that looks like:" + }, + { + "style": "Javascript", + "text": "\"Binance BTC/USDT: Backtesting Session 'Lightning Strike' is starting.\"" + } + ] +} diff --git a/Projects/Superalgos/Schemas/Docs-Nodes/social-bots.json b/Projects/Superalgos/Schemas/Docs-Nodes/social-bots.json index 36f35b99d..6d14ab739 100644 --- a/Projects/Superalgos/Schemas/Docs-Nodes/social-bots.json +++ b/Projects/Superalgos/Schemas/Docs-Nodes/social-bots.json @@ -8,7 +8,7 @@ }, { "style": "Note", - "text": "At present Superalgos only supports Telegram and Discord messaging applications.", + "text": "At present Superalgos only supports Telegram, Discord, and Slack messaging applications.", "updated": 1619547181067 } ], @@ -16,4 +16,4 @@ "text": "A Social Bots node is used to define the bots for each messaging application. These messaging bots are used to send announcements and receive commands used to interact with Superalgos.", "updated": 1618222853055 } -} \ No newline at end of file +} diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/SlackBot.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/SlackBot.js new file mode 100644 index 000000000..497fd84a9 --- /dev/null +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/SlackBot.js @@ -0,0 +1,87 @@ +exports.newSuperalgosBotModulesSlackBot = function (processIndex) { + + const MODULE_NAME = 'Slack Bot' + + let thisObject = { + webhookURL: undefined, + taskParameters: undefined, + format: undefined, + sendMessage: sendMessage, + initialize: initialize, + finalize: finalize + } + + return thisObject + + function initialize(config) { + /* Slack Bot Initialization */ + + try { + thisObject.webhookURL = config.webhookURL + thisObject.taskParameters = { + exchange: TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name, + market: TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + + '/' + + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + } + if (config.format === undefined) { + thisObject.format = "%{MESSAGE}" + } else { + thisObject.format = config.format + } + } catch (err) { + logError("initialize -> err = " + err.stack); + } + + } + + function finalize() {} + + function sendMessage(message) { + const https = require('https') + + try { + message = formatMessage(message) + message = JSON.stringify({text: message}) + } catch (err) { + logError("announce -> Slack JSON message error -> err = " + err) + } + + return new Promise((resolve, reject) => { + const requestOptions = { + method: 'POST', + headers: { 'Content-Type': 'application/json' } + } + + const req = https.request(thisObject.webhookURL, requestOptions, (res) => { + let response = '' + res.on('data', (data) => { response += data }) + res.on('end', () => { resolve(response) }) + }) + + req.on('error', (err) => { + reject(err) + logWarn("announce -> Slack request error -> err = " + err) + }) + + req.write(message) + req.end() + }) + } + + function formatMessage(message) { + formattedMessage = thisObject.format + formattedMessage = formattedMessage.replace('%{EXCHANGE}', thisObject.taskParameters.exchange) + formattedMessage = formattedMessage.replace('%{MARKET}', thisObject.taskParameters.market) + formattedMessage = formattedMessage.replace('%{MESSAGE}', message) + return formattedMessage + } + + function logWarn(message) { + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[WARN] ' + message) + } + + function logError(message) { + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[ERROR] ' + message) + } +} diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/SocialBots.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/SocialBots.js index 4fd29c7f2..fe7736edd 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/SocialBots.js +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/SocialBots.js @@ -24,6 +24,10 @@ exports.newSuperalgosBotModulesSocialBots = function (processIndex) { let config = socialBot.config socialBot.botInstance = TS.projects.superalgos.botModules.discordBot.newSuperalgosBotModulesDiscordBot(processIndex) socialBot.botInstance.initialize(config) + } else if (socialBot.type === "Slack Bot") { + let config = socialBot.config + socialBot.botInstance = TS.projects.superalgos.botModules.slackBot.newSuperalgosBotModulesSlackBot(processIndex) + socialBot.botInstance.initialize(config) } } } @@ -38,7 +42,7 @@ exports.newSuperalgosBotModulesSocialBots = function (processIndex) { try { if (socialBot.type === "Telegram Bot") { socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, text).catch(err => TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> Telegram API error -> err = " + err)) - } else if (socialBot.type === "Discord Bot") { + } else if (socialBot.type === "Discord Bot" ||socialBot.type === "Slack Bot" ) { socialBot.botInstance.sendMessage(text).catch(err => TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> Discord Bot error -> err = " + err)) } } catch (err) { @@ -61,7 +65,7 @@ exports.newSuperalgosBotModulesSocialBots = function (processIndex) { if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.socialBots[prop] !== undefined) { for (let i = 0; i < TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.socialBots[prop].length; i++) { let socialBot = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.socialBots[prop][i] - if (socialBot.type === "Telegram Bot" || socialBot.type === "Discord Bot") { + if (socialBot.type === "Telegram Bot" || socialBot.type === "Discord Bot" || socialBot.type === "Slack Bot") { socialBot.botInstance.finalize() } } @@ -77,7 +81,7 @@ exports.newSuperalgosBotModulesSocialBots = function (processIndex) { if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.socialBots[prop] !== undefined) { for (let i = 0; i < TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.socialBots[prop].length; i++) { let socialBot = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.socialBots[prop][i] - if (socialBot.type === "Telegram Bot" || socialBot.type === "Discord Bot") { + if (socialBot.type === "Telegram Bot" || socialBot.type === "Discord Bot" || socialBot.type === "Slack Bot") { socialBot.botInstance.sendMessage(message) } } diff --git a/Projects/Superalgos/UI/Function-Libraries/ActionSwitch.js b/Projects/Superalgos/UI/Function-Libraries/ActionSwitch.js index 3b1016f58..1ad6b714c 100644 --- a/Projects/Superalgos/UI/Function-Libraries/ActionSwitch.js +++ b/Projects/Superalgos/UI/Function-Libraries/ActionSwitch.js @@ -722,6 +722,11 @@ function newSuperalgosActionSwitch() { UI.projects.superalgos.functionLibraries.socialBotsFunctions.sendDiscordTestMessage(action.node, action.callBackFunction) } break + case 'Send Slack Test Message': + { + UI.projects.superalgos.functionLibraries.socialBotsFunctions.sendSlackTestMessage(action.node, action.callBackFunction) + } + break } } } diff --git a/Projects/Superalgos/UI/Function-Libraries/LearningSessionFunctions.js b/Projects/Superalgos/UI/Function-Libraries/LearningSessionFunctions.js index fb3835fba..6620c9b33 100644 --- a/Projects/Superalgos/UI/Function-Libraries/LearningSessionFunctions.js +++ b/Projects/Superalgos/UI/Function-Libraries/LearningSessionFunctions.js @@ -129,7 +129,7 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() { 'Back Learning Session->Live Learning Session->' + 'Learning Parameters->' + 'Learning Algorithm->Time Range->Time Frame->Heartbeats->User Defined Parameters->' + - 'Social Bots->Telegram Bot->Discord Bot->' + 'Social Bots->Telegram Bot->Discord Bot->Slack Bot->' let session = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node, false, true, true, false, false, lightingPath) diff --git a/Projects/Superalgos/UI/Function-Libraries/SocialBotsFunctions.js b/Projects/Superalgos/UI/Function-Libraries/SocialBotsFunctions.js index 31a387c2b..4b20d5443 100644 --- a/Projects/Superalgos/UI/Function-Libraries/SocialBotsFunctions.js +++ b/Projects/Superalgos/UI/Function-Libraries/SocialBotsFunctions.js @@ -1,7 +1,8 @@ function newSuperalgosFunctionLibrarySocialBotsFunctions() { thisObject = { sendTelegramTestMessage: sendTelegramTestMessage, - sendDiscordTestMessage: sendDiscordTestMessage + sendDiscordTestMessage: sendDiscordTestMessage, + sendSlackTestMessage: sendSlackTestMessage } return thisObject @@ -127,4 +128,59 @@ function newSuperalgosFunctionLibrarySocialBotsFunctions() { } } } + + function sendSlackTestMessage(node, callBackFunction) { + + let webhookURL = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(node.payload, 'webhookURL') + + if (webhookURL === undefined) { + node.payload.uiObject.setErrorMessage('webhookURL parameter not defined.') + callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) + return + } + + let message = "Test message from Superalgos!" + + httpRequestJSON(JSON.stringify({text: message}), webhookURL, onResponse) + + function onResponse(err) { + if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) { + node.payload.uiObject.setInfoMessage('Slack message sent.') + callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE) + } else { + node.payload.uiObject.setErrorMessage('Could not send Slack message. Error Response: ' + err.message) + callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) + } + } + + function httpRequestJSON(pContentToSend, pPath, callBackFunction) { + let xmlHttpRequest = new XMLHttpRequest(); + xmlHttpRequest.onreadystatechange = function () { + if (this.readyState === 4 && this.status === 200) { + callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE, xmlHttpRequest.responseText); + return; + } else if (this.readyState === 4 && (this.status === 404 || this.status === 401 || this.status === 400)) { + callBackFunction({ + result: "Fail", + message: xmlHttpRequest.responseText + }); + return; + } + }; + + if (pContentToSend === undefined) { + xmlHttpRequest.open("GET", pPath, true); + xmlHttpRequest.send(); + } else { + try { + let blob = new Blob([pContentToSend]); + xmlHttpRequest.open("POST", pPath, true); + xmlHttpRequest.send(blob); + } catch (err) { + if (ERROR_LOG === true) { console.log(spacePad(MODULE_NAME, 50) + " : " + "[ERROR] callServer -> err.message = " & err.message); } + callBackFunction({ result: "Fail", message: err.message }) + } + } + } + } } diff --git a/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js b/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js index 3adc57019..a48b4b0ff 100644 --- a/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js +++ b/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js @@ -153,7 +153,7 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { 'Backtesting Session->Paper Trading Session->Forward Testing Session->Live Trading Session->' + 'Trading Parameters->' + 'Session Base Asset->Session Quoted Asset->Time Range->Time Frame->Slippage->Fee Structure->Snapshots->Heartbeats->User Defined Parameters->' + - 'Social Bots->Telegram Bot->Discord Bot->' + + 'Social Bots->Telegram Bot->Discord Bot->Slack Bot->' + 'Exchange Account Asset->Asset->' let session = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node, false, true, true, false, false, lightingPath)