Add: User-Defined-Code for Stages

This commit is contained in:
Philip Love committed 2021-05-13 14:48:10 -04:00
1 parent 3e8ca6a5ae
commit 35b852ff2a
9 files changed
+211 -16

No files matched your search

@@ -64,6 +64,12 @@
"name": "announcements",
"type": "array",
"childType": "Announcement"
},
{
"name": "userDefinedCode",
"type": "node",
"childType": "User Defined Code",
"autoAdd": false
}
],
"propertyNameAtParent": "closeStage"
@@ -9,7 +9,7 @@
"code": "// Type you code"
},
"attachingRules": {
"compatibleTypes": "->Condition->"
"compatibleTypes": "->Condition->User Defined Code->"
},
"menuItems": [
{
@@ -45,6 +45,12 @@
"name": "announcements",
"type": "array",
"childType": "Announcement"
},
{
"name": "userDefinedCode",
"type": "node",
"childType": "User Defined Code",
"autoAdd": false
}
],
"propertyNameAtParent": "manageStage"
@@ -64,6 +64,12 @@
"name": "announcements",
"type": "array",
"childType": "Announcement"
},
{
"name": "userDefinedCode",
"type": "node",
"childType": "User Defined Code",
"autoAdd": false
}
],
"propertyNameAtParent": "openStage"
@@ -51,6 +51,12 @@
"name": "announcements",
"type": "array",
"childType": "Announcement"
},
{
"name": "userDefinedCode",
"type": "node",
"childType": "User Defined Code",
"autoAdd": false
}
],
"propertyNameAtParent": "triggerStage"
@@ -0,0 +1,55 @@
{
"type": "User Defined Code",
"menuItems": [
{
"action": "Configure",
"actionFunction": "uiObject.configEditor.activate",
"label": "Configure",
"iconPathOn": "configuration",
"iconPathOff": "configuration"
},
{
"action": "Add UI Object",
"propertyToCheckFor": "javascriptCode",
"label": "Add Code",
"relatedUiObject": "Javascript Code",
"actionFunction": "payload.executeAction"
},
{
"action": "Delete UI Object",
"askConfirmation": true,
"confirmationLabel": "Confirm to Delete",
"actionFunction": "payload.executeAction",
"label": "Delete",
"iconPathOn": "delete-entity",
"iconPathOff": "delete-entity"
},
{
"action": "Copy Node Path",
"label": "Copy Node Path",
"iconPathOn": "copy-path",
"iconPathOff": "copy-path",
"actionFunction": "payload.executeAction"
}
],
"addLeftIcons": true,
"initialValues": {
"config": "{ \n \"runWhenEnteringStage\": false, \n \"runWhenExitingStage\": false, \n \"runWhileAtStage\": false, \n \"WhileAtStage_whenToRun\": \"first|last\" \n}"
},
"editors": {
"config": true
},
"level": 2,
"attachingRules": {
"compatibleTypes": "->Trigger Stage->Open Stage->Manage Stage->Close Stage->"
},
"childrenNodesProperties": [
{
"name": "javascriptCode",
"type": "array",
"childType": "Javascript Code",
"autoAdd": true
}
],
"propertyNameAtParent": "userDefinedCode"
}
@@ -169,6 +169,7 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
function checkTriggerOff() {
if (tradingEngine.tradingCurrent.strategyTriggerStage.status.value === 'Open') {
checkUserDefinedCode('Trigger Stage', 'Running', 'first');
let strategy = tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value]
let triggerStage = strategy.triggerStage
@@ -246,6 +247,8 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
changeStageStatus('Trigger Stage', 'Closed', 'Position Taken')
changeStageStatus('Open Stage', 'Opening')
changeStageStatus('Manage Stage', 'Opening')
} else {
checkUserDefinedCode('Trigger Stage', 'Running', 'last');
}
}
}
@@ -299,7 +302,7 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
tradingPositionModuleObject.initialTargets(tradingSystemStage, tradingEngineStage)
initializeStageTargetSize()
/* From here on, the stage is officialy Open */
/* From here on, the stage is officially Open */
changeStageStatus('Open Stage', 'Open')
}
}
@@ -311,6 +314,7 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
While the Open Stage is Open, we do our regular stuff: place orders and check
what happened to the orders already placed.
*/
checkUserDefinedCode('Open Stage', 'Running', 'first');
let tradingSystemStage = tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].openStage
let tradingEngineStage = tradingEngine.tradingCurrent.strategyOpenStage
let executionNode = tradingSystemStage.openExecution
@@ -324,6 +328,11 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
tradingEngineStage
)
checkIfStageNeedsToBeClosed(tradingEngineStage, tradingSystemStage, 'Open Stage')
/* User Defined Code if runWhileAtStage==true */
if (tradingEngine.tradingCurrent.strategyOpenStage.status.value === 'Open') {
checkUserDefinedCode('Open Stage', 'Running', 'last');
}
}
}
@@ -410,7 +419,7 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
if (tradingEngine.tradingCurrent.strategyManageStage.status.value === 'Opening') {
let strategy = tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value]
let manageStage = strategy.manageStage
/*
The system allows the user not to define a Manage Stage, because the Manage Stage is optional.
Here we are going to see if that is the case and if it is, we will inmidiatelly consider
@@ -431,6 +440,7 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
function runWhenStatusIsOpen() {
/* Open Status Procedure */
if (tradingEngine.tradingCurrent.strategyManageStage.status.value === 'Open') {
checkUserDefinedCode('Manage Stage', 'Running', 'first');
let strategy = tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value]
let manageStage = strategy.manageStage
@@ -450,6 +460,11 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
/* Checking if Stop or Take Profit were hit */
checkStopLossOrTakeProfitWasHit()
/* If User Defined Code exists check for runWhileAtStage */
if (tradingEngine.tradingCurrent.strategyManageStage.status.value === 'Open') {
checkUserDefinedCode('Manage Stage', 'Running', 'last');
}
}
function calculateStopLoss() {
@@ -846,6 +861,7 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
/*
This will happen as long as the Close Stage is Open.
*/
checkUserDefinedCode('Close Stage', 'Running', 'first');
let tradingSystemStage = tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].closeStage
let tradingEngineStage = tradingEngine.tradingCurrent.strategyCloseStage
let executionNode = tradingSystemStage.closeExecution
@@ -859,6 +875,10 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
)
checkIfStageNeedsToBeClosed(tradingEngineStage, tradingSystemStage, 'Close Stage')
/* If User Defined Code exists check for runWhileAtStage */
if (tradingEngine.tradingCurrent.strategyCloseStage.status.value === 'Open') {
checkUserDefinedCode('Close Stage', 'Running', 'last');
}
}
}
@@ -1122,9 +1142,11 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
}
if (stage.status.value === 'Open') {
openStage(stage)
checkUserDefinedCode(stageName, 'Open')
}
if (stage.status.value === 'Closed') {
closeStage(stage)
checkUserDefinedCode(stageName, 'Closed')
}
/*
@@ -1228,4 +1250,57 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) {
}
throw 'Error Already Recorded'
}
}
/* checkUserDefinedCode(): Checks if User Defined Code exists and processes if applicable. */
function checkUserDefinedCode(stage, status, when) {
let tradingSystemStage = getTradingSystemStage(stage);
if (tradingSystemStage.userDefinedCode !== undefined) {
if (status === 'Running' && when !== tradingSystemStage.userDefinedCode.config.WhileAtStage_whenToRun) { return; }
switch(status) {
case 'Open' : {
if (tradingSystemStage.userDefinedCode.config.runWhenEnteringStage) {
tradingSystem.evalUserCode(tradingSystemStage, 'User Defined Code');
}
break;
}
case 'Running' : {
if (tradingSystemStage.userDefinedCode.config.runWhileAtStage &&
tradingSystemStage.userDefinedCode.config.WhileAtStage_whenToRun === when) {
tradingSystem.evalUserCode(tradingSystemStage, 'User Defined Code');
}
break;
}
case 'Closed' : {
if (tradingSystemStage.userDefinedCode.config.runWhenExitingStage) {
tradingSystem.evalUserCode(tradingSystemStage, 'User Defined Code');
}
break;
}
}
}
}
/* getTradingSystemStage(): takes stage name returns stage object. */
function getTradingSystemStage(stage) {
switch(stage) {
case 'Trigger Stage' : {
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].triggerStage;
break;
}
case 'Open Stage' : {
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].openStage;
break;
}
case 'Manage Stage' : {
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].manageStage;
break
}
case 'Close Stage' : {
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].closeStage;
break;
}
}
}
}
@@ -13,7 +13,7 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) {
finalize: finalize
}
/*
/*
These 3 are the main data structures available to users
when writing conditions and formulas.
*/
@@ -74,6 +74,10 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) {
evalNode(startingNode, 'Formulas', descendentOfNodeType)
}
tradingSystem.evalUserCode = function (startingNode, descendentOfNodeType) {
evalNode(startingNode, 'User Codes', descendentOfNodeType);
}
tradingSystem.addError = function (errorDataArray) {
/*
This function adds to the array of error info a rate.
@@ -87,7 +91,7 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) {
tradingSystem.addWarning = function (warningDataArray) {
/*
This function adds to the array of warning info a rate.
This function adds to the array of warning info a rate.
This rate will later help plotting the warning at the
charts.
*/
@@ -98,7 +102,7 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) {
tradingSystem.addInfo = function (infoDataArray) {
/*
This function adds to the array of warning info a rate.
This function adds to the array of warning info a rate.
This rate will later help plotting the warning at the
charts.
*/
@@ -108,9 +112,9 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) {
}
function isItInside(elementWithTimestamp, elementWithBeginEnd) {
/*
The function is to allow in Conditions and Formulas to easily
know when an element with timestamp (like the ones of
/*
The function is to allow in Conditions and Formulas to easily
know when an element with timestamp (like the ones of
single files) are inside the time range
of an element with a time range, like a candle.
*/
@@ -167,8 +171,8 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) {
}
function updateChart(pChart, pExchange, pMarket) {
/*
We need these 3 data structures to be a local objects
/*
We need these 3 data structures to be a local objects
accessible while evaluating conditions and formulas.
*/
chart = pChart
@@ -216,7 +220,7 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) {
tradingStagesModuleObject.cycleBasedStatistics()
} catch (err) {
/*
/*
If an error ocurred during execution, it was alreeady logged and
included at the errors array. That means we need to do nothing here,
just prevent the execution to be halted for not handling exceptions.
@@ -258,6 +262,15 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) {
}
}
/* Here we check if there is a User Defined-Javascript Code to be evaluated: */
if (node.type === 'Javascript Code' && evaluating === 'User Codes') {
if (node.code !== undefined) {
if (isDescendent === true) {
evalJSCode(node);
}
}
}
/* Now we go down through all this node children */
let schemaDocument = TS.projects.superalgos.globals.taskConstants.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
if (schemaDocument === undefined) { return }
@@ -395,5 +408,31 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) {
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalFormula -> value = ' + value)
}
}
function evalJSCode(node) {
let value
let errorMessage
let docs
try {
value = eval(node.code);
} catch (err) {
value = 0
errorMessage = err.message
docs = {
project: 'Superalgos',
category: 'Topic',
type: 'TS LF Trading Bot Error - Evaluating User Code Error',
placeholder: {}
}
TS.projects.superalgos.utilities.docsFunctions.buildPlaceholder(docs, err, node.name, node.code, undefined)
}
if (errorMessage !== undefined) {
tradingSystem.addError([node.id, errorMessage, docs])
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalFormula -> errorMessage = ' + errorMessage)
return
}
}
}
@@ -107,7 +107,8 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() {
'Size In Base Asset->Size In Quoted Asset->Position Rate->Formula->' +
'Situation->Condition->Javascript Code->' +
'Market Order->Limit Order->' +
'Simulated Exchange Events->Simulated Partial Fill->Simulated Actual Rate->Simulated Fees Paid->Formula->'
'Simulated Exchange Events->Simulated Partial Fill->Simulated Actual Rate->Simulated Fees Paid->Formula->' +
'User Defined Code->Javascript Code->'
let tradingSystem = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node.tradingSystemReference.payload.referenceParent, false, true, true, false, false, lightingPath)
@@ -145,7 +146,8 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() {
'Begin->End->Exit Type->Status->Begin Rate->End Rate->Stage Base Asset->Stage Quoted Asset->Size Placed->Target Size->Size Filled->Fees Paid->Stage Defined In->' +
'Serial Number->Identifier->Begin->End->Begin Rate->End Rate->Strategy Name->Status->Exit Type->' +
'Balance->Begin Balance->End Balance->' +
'Index->Situation Name->Formula->Periods->'
'Index->Situation Name->Formula->Periods->' +
'User Variables->User Defined Variable->'
let tradingEngine = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node.tradingEngineReference.payload.referenceParent, false, true, true, false, false, lightingPath)