initial commit of slack bot

This commit is contained in:
Brett Taylor committed 2021-05-11 18:30:25 -04:00
1 parent 631a702499
commit 3574ee7d59
13 files changed
+311 -8

No files matched your search

+7
View File
@@ -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",
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 270 270" style="enable-background:new 0 0 270 270;" xml:space="preserve">
<style type="text/css">
.st0{fill:#E01E5A;}
.st1{fill:#36C5F0;}
.st2{fill:#2EB67D;}
.st3{fill:#ECB22E;}
</style>
<g>
<g>
<path class="st0" d="M99.4,151.2c0,7.1-5.8,12.9-12.9,12.9c-7.1,0-12.9-5.8-12.9-12.9c0-7.1,5.8-12.9,12.9-12.9h12.9V151.2z"/>
<path class="st0" d="M105.9,151.2c0-7.1,5.8-12.9,12.9-12.9s12.9,5.8,12.9,12.9v32.3c0,7.1-5.8,12.9-12.9,12.9
s-12.9-5.8-12.9-12.9V151.2z"/>
</g>
<g>
<path class="st1" d="M118.8,99.4c-7.1,0-12.9-5.8-12.9-12.9c0-7.1,5.8-12.9,12.9-12.9s12.9,5.8,12.9,12.9v12.9H118.8z"/>
<path class="st1" d="M118.8,105.9c7.1,0,12.9,5.8,12.9,12.9s-5.8,12.9-12.9,12.9H86.5c-7.1,0-12.9-5.8-12.9-12.9
s5.8-12.9,12.9-12.9H118.8z"/>
</g>
<g>
<path class="st2" d="M170.6,118.8c0-7.1,5.8-12.9,12.9-12.9c7.1,0,12.9,5.8,12.9,12.9s-5.8,12.9-12.9,12.9h-12.9V118.8z"/>
<path class="st2" d="M164.1,118.8c0,7.1-5.8,12.9-12.9,12.9c-7.1,0-12.9-5.8-12.9-12.9V86.5c0-7.1,5.8-12.9,12.9-12.9
c7.1,0,12.9,5.8,12.9,12.9V118.8z"/>
</g>
<g>
<path class="st3" d="M151.2,170.6c7.1,0,12.9,5.8,12.9,12.9c0,7.1-5.8,12.9-12.9,12.9c-7.1,0-12.9-5.8-12.9-12.9v-12.9H151.2z"/>
<path class="st3" d="M151.2,164.1c-7.1,0-12.9-5.8-12.9-12.9c0-7.1,5.8-12.9,12.9-12.9h32.3c7.1,0,12.9,5.8,12.9,12.9
c0,7.1-5.8,12.9-12.9,12.9H151.2z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

@@ -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"
}
@@ -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"
@@ -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.\""
}
]
}
@@ -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
}
}
}
@@ -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)
}
}
@@ -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)
}
}
@@ -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
}
}
}
@@ -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)
@@ -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 })
}
}
}
}
}
@@ -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)