diff --git a/Projects/Superalgos/Icons-SVG-Sources/nodes/social-bot-command.svg b/Projects/Superalgos/Icons-SVG-Sources/nodes/social-bot-command.svg new file mode 100644 index 000000000..f99bd7c9c --- /dev/null +++ b/Projects/Superalgos/Icons-SVG-Sources/nodes/social-bot-command.svg @@ -0,0 +1,182 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Projects/Superalgos/Icons/social-bot-command.png b/Projects/Superalgos/Icons/social-bot-command.png new file mode 100644 index 000000000..0318ce9ae Binary files /dev/null and b/Projects/Superalgos/Icons/social-bot-command.png differ diff --git a/Projects/Superalgos/Schemas/App-Schema/formula.json b/Projects/Superalgos/Schemas/App-Schema/formula.json index 899eb3258..5acb5a1e1 100644 --- a/Projects/Superalgos/Schemas/App-Schema/formula.json +++ b/Projects/Superalgos/Schemas/App-Schema/formula.json @@ -28,7 +28,7 @@ }, "level": 4, "attachingRules": { - "compatibleTypes": "->Target Size In Base Asset->Target Size In Quoted Asset->Target Rate->Phase->Simulated Actual Rate->Situation->Indicator Function->Order Rate->" + "compatibleTypes": "->Target Size In Base Asset->Target Size In Quoted Asset->Target Rate->Phase->Simulated Actual Rate->Situation->Indicator Function->Order Rate->Social Bot Command->" }, "propertyNameAtParent": "formula" } \ No newline at end of file diff --git a/Projects/Superalgos/Schemas/App-Schema/social-bot-command.json b/Projects/Superalgos/Schemas/App-Schema/social-bot-command.json new file mode 100644 index 000000000..dd25f533a --- /dev/null +++ b/Projects/Superalgos/Schemas/App-Schema/social-bot-command.json @@ -0,0 +1,49 @@ +{ + "type": "Social Bot Command", + "editors": { + "config": true + }, + "menuItems": [ + { + "action": "Configure", + "actionFunction": "uiObject.configEditor.activate", + "label": "Configure", + "iconPathOn": "configuration", + "iconPathOff": "configuration" + }, + { + "action": "Add UI Object", + "disableIfPropertyIsDefined": true, + "propertyToCheckFor": "formula", + "label": "Add Formula", + "relatedUiObject": "Formula", + "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\"name\": \"Enter the name of the command without a leading slash\"\n}" + }, + "addLeftIcons": true, + "level": 4, + "attachingRules": { + "compatibleTypes": "->Telegram Bot->" + }, + "childrenNodesProperties": [ + { + "name": "formula", + "type": "node", + "childType": "Formula", + "autoAdd": true + } + ], + "propertyNameAtParent": "socialBotCommand" +} diff --git a/Projects/Superalgos/Schemas/App-Schema/telegram-bot.json b/Projects/Superalgos/Schemas/App-Schema/telegram-bot.json index 6a9829a18..809452173 100644 --- a/Projects/Superalgos/Schemas/App-Schema/telegram-bot.json +++ b/Projects/Superalgos/Schemas/App-Schema/telegram-bot.json @@ -11,6 +11,12 @@ "iconPathOn": "configuration", "iconPathOff": "configuration" }, + { + "action": "Add UI Object", + "label": "Add Social Bot Command", + "relatedUiObject": "Social Bot Command", + "actionFunction": "payload.executeAction" + }, { "action": "Send Telegram Test Message", "label": "Send Telegram Test Message", @@ -36,6 +42,13 @@ "attachingRules": { "compatibleTypes": "->Social Bots->" }, - "childrenNodesProperties": [], + "childrenNodesProperties": [ + { + "name": "socialBotCommand", + "type": "array", + "childType": "Social Bot Command", + "autoAdd": true + } + ], "propertyNameAtParent": "telegramBots" } \ No newline at end of file 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 fe7736edd..e334380d9 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/SocialBots.js +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/SocialBots.js @@ -16,16 +16,15 @@ exports.newSuperalgosBotModulesSocialBots = function (processIndex) { if (prop.toLowerCase().includes("Bots".toLowerCase())) { 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] + let config = socialBot.config + let commands = socialBot.socialBotCommand if (socialBot.type === "Telegram Bot") { - let config = socialBot.config socialBot.botInstance = TS.projects.superalgos.botModules.telegramBot.newSuperalgosBotModulesTelegramBot(processIndex) - socialBot.botInstance.initialize(config.botToken, config.chatId) + socialBot.botInstance.initialize(config, commands) } else if (socialBot.type === "Discord Bot") { - 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) } diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/TelegramBot.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/TelegramBot.js index 2d47ba3bc..a5b34f5ed 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/TelegramBot.js +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Announcements/TelegramBot.js @@ -14,9 +14,12 @@ exports.newSuperalgosBotModulesTelegramBot = function (processIndex) { return thisObject - function initialize(botToken, chatId) { + function initialize(config, commands) { /* Telegram Bot Initialization */ try { + let botToken = config.botToken + let chatId = config.chatId + thisObject.chatId = chatId const Telegraf = require('telegraf') @@ -25,16 +28,17 @@ exports.newSuperalgosBotModulesTelegramBot = function (processIndex) { thisObject.telegramBot.start((ctx) => ctx.reply('Hi! I am the Telegram Bot that will tell you what happens with your trading session.')) thisObject.telegramBot.help((ctx) => ctx.replyWithHTML('SUPERALGOS BOT HELP\n\n' + '• Use /stop to stop the session.\n' + - '• Use /help to receive this help message.\n' + - '• Use /balances for episode balances.\n' + - '• Use /counters for episode counters.\n' + - '• Use /statistics for episode statistics.\n' + - '• Use /uptime for episode uptime.')) + '• Use /help to receive this help message.\n\n' + + 'Additional commands can be configured using the Social Bot Command node.')) thisObject.telegramBot.command('stop', (ctx) => TS.projects.superalgos.functionLibraries.sessionFunctions.stopSession(processIndex, 'by command from Telegram.')) - thisObject.telegramBot.command('balances', (ctx) => interpretCommand('balances', processIndex)) - thisObject.telegramBot.command('uptime', (ctx) => interpretCommand('uptime', processIndex)) - thisObject.telegramBot.command('statistics', (ctx) => interpretCommand('statistics', processIndex)) - thisObject.telegramBot.command('counters', (ctx) => interpretCommand('counters', processIndex)) + + /* Set up additional commands for each Social Bot Command node */ + if(commands !== undefined) { + for (let i = 0; i < commands.length; i++) { + thisObject.telegramBot.command(commands[i].config.name, (ctx) => interpretCommand(commands[i].formula.code, processIndex)) + } + } + thisObject.telegramBot.launch() const Telegram = require('telegraf/telegram') @@ -67,72 +71,28 @@ exports.newSuperalgosBotModulesTelegramBot = function (processIndex) { let message let tradingEngine - let tradingEpisode - let sessionNode - let sessionName + let tradingSystem + let sessionParameters - tradingEngine = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingEngine - tradingEpisode = tradingEngine.tradingCurrent.tradingEpisode + if(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE !== undefined) { + tradingEngine = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingEngine + tradingSystem = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingSystem + } + sessionParameters = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters - sessionNode = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE - sessionName = sessionNode.name + let 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 + } - - switch (command) { - case 'balances': { - - let baseAsset = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName - let quotedAsset = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName - - message = "SUPERALGOS BALANCES\n\nTrading Session: " + sessionName + - "\nPair: " + baseAsset + "/" + quotedAsset + - "\nBase Asset: " + tradingEpisode.episodeBaseAsset.balance.value + " " + baseAsset + - "\nQuoted Asset: " + tradingEpisode.episodeQuotedAsset.balance.value + " " + quotedAsset - break - } - case 'uptime': { - - let sessionBegin = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_BEGIN - - let dateBegin = new Date(sessionBegin) - let dateNow = new Date(); - - let seconds = Math.floor((dateNow - (dateBegin))/1000) - let minutes = Math.floor(seconds/60) - let hours = Math.floor(minutes/60) - let days = Math.floor(hours/24) - - hours = hours-(days*24) - minutes = minutes-(days*24*60)-(hours*60) - seconds = seconds-(days*24*60*60)-(hours*60*60)-(minutes*60) - - let uptime = days + "D, " + hours + "H, " + minutes + "M, " + seconds + "S" - - message = "SUPERALGOS UPTIME\n\nTrading Session: " + sessionName + - "\nUptime: " + uptime - break - } - case 'statistics': { - - message = "SUPERALGOS STATISTICS\n\nTrading Session: " + sessionName + - "\nDays: " + (tradingEpisode.tradingEpisodeStatistics.days.value).toFixed(2) + - "\nProfit Loss: " + tradingEpisode.tradingEpisodeStatistics.profitLoss.value + - "\nROI: " + (tradingEpisode.tradingEpisodeStatistics.ROI.value).toFixed(2) + - "\nAnnualized Rate Of Return: " + (tradingEpisode.tradingEpisodeStatistics.annualizedRateOfReturn.value).toFixed(2) + - "\nHit Fail: " + tradingEpisode.tradingEpisodeStatistics.hitFail.value - break - } - case 'counters': { - - message = "SUPERALGOS COUNTERS\n\nTrading Session: " + sessionName + - "\nPeriods: " + tradingEpisode.tradingEpisodeCounters.periods.value + - "\nStrategies: " + tradingEpisode.tradingEpisodeCounters.strategies.value + - "\nPositions: " + tradingEpisode.tradingEpisodeCounters.positions.value + - "\nOrders: " + tradingEpisode.tradingEpisodeCounters.orders.value + - "\nHits: " + tradingEpisode.tradingEpisodeCounters.hits.value + - "\nFails: " + tradingEpisode.tradingEpisodeCounters.fails.value - break - } + try { + message = eval(command) + } catch (err) { + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME, + "[WARN] interpretCommand -> Telegram API error evaluating user formula -> err = " + err.stack) + return } thisObject.telegramAPI.sendMessage(thisObject.chatId, message, {parse_mode: 'HTML'}).catch(err => TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME, diff --git a/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js b/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js index d70d32fb5..f59315da3 100644 --- a/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js +++ b/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js @@ -156,6 +156,7 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { '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->Slack Bot->' + + 'Social Bot Command->Formula->' + 'Exchange Account Asset->Asset->' let session = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node, false, true, true, false, false, lightingPath)