diff --git a/Projects/ProjectsSchema.json b/Projects/ProjectsSchema.json index 5f20a722c..a935d28de 100644 --- a/Projects/ProjectsSchema.json +++ b/Projects/ProjectsSchema.json @@ -120,6 +120,11 @@ "name": "Workspace Functions", "propertyName": "workspaceFunctions", "functionName": "newSuperalgosFunctionLibraryWorkspaceFunctions" + }, + { + "name": "Social Bots Functions", + "propertyName": "socialBotsFunctions", + "functionName": "newSuperalgosFunctionLibrarySocialBotsFunctions" } ], "utilities": [ diff --git a/Projects/Superalgos/Icons-SVG-Sources/menu/test.svg b/Projects/Superalgos/Icons-SVG-Sources/menu/test.svg new file mode 100644 index 000000000..bff868d7a --- /dev/null +++ b/Projects/Superalgos/Icons-SVG-Sources/menu/test.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Projects/Superalgos/Icons/test-entity.png b/Projects/Superalgos/Icons/test-entity.png new file mode 100644 index 000000000..c42733847 Binary files /dev/null and b/Projects/Superalgos/Icons/test-entity.png differ diff --git a/Projects/Superalgos/Schemas/AppSchema.json b/Projects/Superalgos/Schemas/AppSchema.json index a91037675..b28029cc8 100644 --- a/Projects/Superalgos/Schemas/AppSchema.json +++ b/Projects/Superalgos/Schemas/AppSchema.json @@ -14879,6 +14879,13 @@ "iconPathOn": "configuration", "iconPathOff": "configuration" }, + { + "action": "Send Telegram Test Message", + "label": "Send Telegram Test Message", + "iconPathOn": "test-entity", + "iconPathOff": "test-entity", + "actionFunction": "payload.executeAction" + }, { "action": "Delete UI Object", "askConfirmation": true, diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js index 876a4a3a8..52efea02d 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js @@ -800,6 +800,7 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) { runWhenStatusIsOpening() await runWhenStatusIsOpen() + await runWhenStatusIsClosing() function runWhenStatusIsOpening() { @@ -861,6 +862,58 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) { } } + async function runWhenStatusIsClosing() { + /* Closing Status Procedure */ + if (tradingEngine.tradingCurrent.strategyCloseStage.status.value === 'Closing') { + /* + During the closing stage status, we do not place new orders, just check + if the ones placed were filled, and cancel the ones not filled. + */ + let tradingSystemStage = tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].closeStage + let executionNode = tradingSystemStage.closeExecution + + /* + Check if there are unfilled orders, we will check if they were executed, + and cancel the ones that were not. + */ + tradingSystem.evalConditions(tradingSystemStage, 'Close Execution') + tradingSystem.evalFormulas(tradingSystemStage, 'Close Execution') + + await tradingExecutionModuleObject.runExecution( + executionNode, + tradingEngine.tradingCurrent.strategyCloseStage + ) + + /* + The Closing is finished when the sizeFilled + feesPaid reaches the sizePlaced. + This can happens either because we update the sizeFilled value when we see + at the exchange that orders were filled, or we reduce the sizePlaced when + we cancel not yet filled orders. Here it does not matter the targetSize since + this status represent a force closure of this stage. + */ + switch (tradingEngine.tradingCurrent.strategyCloseStage.stageDefinedIn.value) { + case 'Base Asset': { + if ( + tradingEngine.tradingCurrent.strategyCloseStage.stageBaseAsset.sizeFilled.value >= + tradingEngine.tradingCurrent.strategyCloseStage.stageBaseAsset.sizePlaced.value + ) { + changeStageStatus('Close Stage', 'Closed') + } + break + } + case 'Quoted Asset': { + if ( + tradingEngine.tradingCurrent.strategyCloseStage.stageQuotedAsset.sizeFilled.value >= + tradingEngine.tradingCurrent.strategyCloseStage.stageQuotedAsset.sizePlaced.value + ) { + changeStageStatus('Close Stage', 'Closed') + } + break + } + } + } + } + function initializeStageTargetSize() { /* Validations that all needed nodes are there. @@ -887,6 +940,7 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) { initialized to their defualts. */ if (tradingEngine.tradingCurrent.position.status.value !== 'Open' && tradingEngine.tradingCurrent.position.status.value !== 'Closing') { return } + if (tradingEngine.tradingCurrent.position.status.value !== 'Close' && tradingEngine.tradingCurrent.position.status.value !== 'Closing') { return } if ( ( tradingEngine.tradingCurrent.strategyTriggerStage.status.value === 'Closed' || diff --git a/Projects/Superalgos/UI/Function-Libraries/ActionSwitch.js b/Projects/Superalgos/UI/Function-Libraries/ActionSwitch.js index da50856fe..5e2324136 100644 --- a/Projects/Superalgos/UI/Function-Libraries/ActionSwitch.js +++ b/Projects/Superalgos/UI/Function-Libraries/ActionSwitch.js @@ -712,6 +712,11 @@ function newSuperalgosActionSwitch() { UI.projects.superalgos.spaces.floatingSpace.uiObjectConstructor.createUiObject(true, action.node.payload) } break + case 'Send Telegram Test Message': + { + UI.projects.superalgos.functionLibraries.socialBotsFunctions.sendTelegramTestMessage(action.node, action.callBackFunction) + } + break } } } diff --git a/Projects/Superalgos/UI/Function-Libraries/SocialBotsFunctions.js b/Projects/Superalgos/UI/Function-Libraries/SocialBotsFunctions.js new file mode 100644 index 000000000..ad4be83fb --- /dev/null +++ b/Projects/Superalgos/UI/Function-Libraries/SocialBotsFunctions.js @@ -0,0 +1,73 @@ +function newSuperalgosFunctionLibrarySocialBotsFunctions() { + thisObject = { + sendTelegramTestMessage: sendTelegramTestMessage + } + + return thisObject + + function sendTelegramTestMessage(node, callBackFunction) { + + let botToken = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(node.payload, 'botToken') + let chatId = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(node.payload, 'chatId') + + if (botToken === undefined) { + node.payload.uiObject.setErrorMessage('botToken parameter not defined.') + callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) + return + } + + if (chatId === undefined) { + node.payload.uiObject.setErrorMessage('chatId parameter not defined.') + callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) + return + } + + let params = { + text: "Test Message from Superalgos", + chat_id: chatId + } + + httpRequestJSON(JSON.stringify(params),"https://api.telegram.org/bot" + botToken + "/sendMessage", onResponse) + + function onResponse(err) { + if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) { + node.payload.uiObject.setInfoMessage('Telegram message sent.') + callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE) + } else { + node.payload.uiObject.setErrorMessage('Could not send Telegram 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: JSON.parse(xmlHttpRequest.responseText).description, + code: JSON.parse(xmlHttpRequest.responseText).error_code + }); + return; + } + }; + + if (pContentToSend === undefined) { + xmlHttpRequest.open("GET", pPath, true); + xmlHttpRequest.send(); + } else { + try { + let blob = new Blob([pContentToSend], { type: 'application/json' }); + 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 b16c7e12d..b4e025336 100644 --- a/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js +++ b/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js @@ -56,10 +56,36 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { let eventsServerClient = UI.projects.superalgos.spaces.designSpace.workspace.eventsServerClients.get(networkNode.id) - node.payload.uiObject.run(eventsServerClient, callBackFunction) - let key = node.name + '-' + node.type + '-' + node.id + /* Setup Listener to check Parent Task Status of the Session */ + let eventSubscriptionIdOnStatus + let eventHandlerKey = "Task Client - " + node.payload.parentNode.payload.parentNode.payload.parentNode.id + + eventsServerClient.listenToEvent(eventHandlerKey, 'Task Status', undefined, node.id, onResponse, onStatus) + + function onResponse(message) { + eventSubscriptionIdOnStatus = message.eventSubscriptionId + } + + function onStatus(message) { + eventsServerClient.stopListening(eventHandlerKey, eventSubscriptionIdOnStatus, node.id) + + /* If Task is Not Running Display Error */ + if (message.event.status === 'Task Process Not Running') { + node.payload.uiObject.setErrorMessage('Parent Task Not Running.') + callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) + } else { + node.payload.uiObject.run(eventsServerClient, callBackFunction) + } + } + + /* Raise Event to Check Task Status */ + let eventKey = {} + eventKey.taskId = node.payload.parentNode.payload.parentNode.payload.parentNode.id + + eventsServerClient.raiseEvent("Task Manager", 'Task Status', eventKey) + let lightingPath = '' + 'Trading System->' + 'Dynamic Indicators->Indicator Function->Formula->' + diff --git a/Projects/Superalgos/UI/Spaces/Design-Space/Workspace.js b/Projects/Superalgos/UI/Spaces/Design-Space/Workspace.js index 2cda4ca82..64667840a 100644 --- a/Projects/Superalgos/UI/Spaces/Design-Space/Workspace.js +++ b/Projects/Superalgos/UI/Spaces/Design-Space/Workspace.js @@ -112,12 +112,16 @@ function newWorkspace() { function onIndexingFinished() { setupEventsServerClients() - setTimeout(runTasksAndSessions, 10000) + runTasksAndSessions() + thisObject.enabled = true UI.projects.superalgos.spaces.cockpitSpace.initializePosition() CAN_SPACES_DRAW = true thisObject.isInitialized = true + + playTutorials() + savingWorkspaceIntervalId = setInterval(saveWorkspace, 60000) UI.projects.superalgos.utilities.statusBar.changeStatus("Displaying the UI...") } @@ -132,6 +136,9 @@ function newWorkspace() { executeAction({ name: 'Syncronize Tasks', project: 'Superalgos' }) executeAction({ name: 'Syncronize Trading Sessions', project: 'Superalgos' }) executeAction({ name: 'Syncronize Learning Sessions', project: 'Superalgos' }) + } + + function playTutorials() { executeAction({ name: 'Play Tutorials', project: 'Superalgos' }) }