diff --git a/FloatingSpace/StrategyPart.js b/FloatingSpace/StrategyPart.js index 5e6bc1769..7841815bd 100644 --- a/FloatingSpace/StrategyPart.js +++ b/FloatingSpace/StrategyPart.js @@ -225,7 +225,11 @@ function newStrategyPart () { compatibleSubType = undefined break case 'Position Size': - compatibleType = '->' + 'Trigger Stage' + compatibleType = '->' + 'Initial Definition' + compatibleSubType = undefined + break + case 'Position Rate': + compatibleType = '->' + 'Initial Definition' compatibleSubType = undefined break case 'Take Position Event': @@ -257,7 +261,7 @@ function newStrategyPart () { compatibleSubType = undefined break case 'Formula': - compatibleType = '->' + 'Base Asset' + '->' + 'Position Size' + '->' + 'Phase' + compatibleType = '->' + 'Base Asset' + '->' + 'Position Size' + '->' + 'Position Rate' + '->' + 'Phase' compatibleSubType = undefined break case 'Next Phase Event': @@ -297,6 +301,7 @@ function newStrategyPart () { if (thisObject.payload.node.type === 'Manage Stage' && nearbyNode.manageStage !== undefined) { continue } if (thisObject.payload.node.type === 'Close Stage' && nearbyNode.closeStage !== undefined) { continue } if (thisObject.payload.node.type === 'Position Size' && nearbyNode.positionSize !== undefined) { continue } + if (thisObject.payload.node.type === 'Position Rate' && nearbyNode.positionRate !== undefined) { continue } if (thisObject.payload.node.type === 'Take Position Event' && nearbyNode.takePosition !== undefined) { continue } if (thisObject.payload.node.type === 'Trigger Off Event' && nearbyNode.triggerOff !== undefined) { continue } if (thisObject.payload.node.type === 'Trigger On Event' && nearbyNode.triggerOn !== undefined) { continue } diff --git a/FloatingSpace/StrategyPartConstructor.js b/FloatingSpace/StrategyPartConstructor.js index 378d9a724..a998a8b1c 100644 --- a/FloatingSpace/StrategyPartConstructor.js +++ b/FloatingSpace/StrategyPartConstructor.js @@ -549,20 +549,7 @@ function newStrategyPartConstructor () { rawRadius: 8, targetRadius: 0, currentRadius: 0, - angle: -60 - }, - { - action: 'Add Position Size', - actionFunction: payload.onMenuItemClick, - label: 'Add Position Size', - visible: false, - iconPathOn: 'responsive', - iconPathOff: 'responsive', - relatedStrategyPart: 'Position Size', - rawRadius: 8, - targetRadius: 0, - currentRadius: 0, - angle: -20 + angle: -40 }, { action: 'Delete Trigger Stage', @@ -576,7 +563,7 @@ function newStrategyPartConstructor () { rawRadius: 8, targetRadius: 0, currentRadius: 0, - angle: 20 + angle: 0 }, { action: 'Download', @@ -588,7 +575,7 @@ function newStrategyPartConstructor () { rawRadius: 8, targetRadius: 0, currentRadius: 0, - angle: 60 + angle: 40 }] break } @@ -881,7 +868,92 @@ function newStrategyPartConstructor () { askConfirmation: true, confirmationLabel: 'Confirm to Delete', actionFunction: payload.onMenuItemClick, - label: 'Delete Trading System', + label: 'Delete Position Size', + visible: false, + iconPathOn: 'trash', + iconPathOff: 'trash', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -40 + }, + { + action: 'Add Formula', + actionFunction: payload.onMenuItemClick, + label: 'Add Formula', + visible: false, + iconPathOn: 'pipette', + iconPathOff: 'pipette', + relatedStrategyPart: 'Formula', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 0 + }, + { + action: 'Download', + actionFunction: payload.onMenuItemClick, + label: 'Download', + visible: false, + iconPathOn: 'upload', + iconPathOff: 'upload', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 40 + }] + break + } + case 'Position Rate': { + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + actionStatus: floatingObject.getPinStatus, + currentStatus: true, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Tense / Untense', + actionFunction: floatingObject.tensionToggle, + actionStatus: floatingObject.getTensionStatus, + currentStatus: false, + label: undefined, + visible: false, + iconPathOn: 'compass', + iconPathOff: 'headphones', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 180 + }, + { + action: 'Freeze / Unfreeze', + actionFunction: floatingObject.freezeToggle, + actionStatus: floatingObject.getFreezeStatus, + currentStatus: true, + label: undefined, + visible: false, + iconPathOn: 'targeting', + iconPathOff: 'broken-link', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 135 + }, + { + action: 'Delete Position Rate', + askConfirmation: true, + confirmationLabel: 'Confirm to Delete', + actionFunction: payload.onMenuItemClick, + label: 'Delete Position Rate', visible: false, iconPathOn: 'trash', iconPathOff: 'trash', @@ -2012,6 +2084,10 @@ function newStrategyPartConstructor () { level_3() break } + case 'Position Rate': { + level_3() + break + } case 'Trigger On Event': { level_3() break @@ -2178,4 +2254,3 @@ function newStrategyPartConstructor () { payload.uiObject = undefined } } - diff --git a/FloatingSpace/StrategyPartTitle.js b/FloatingSpace/StrategyPartTitle.js index aa239fa0c..27d0652d9 100644 --- a/FloatingSpace/StrategyPartTitle.js +++ b/FloatingSpace/StrategyPartTitle.js @@ -81,6 +81,9 @@ function newStrategyPartTitle () { case 'Position Size': { break } + case 'Position Rate': { + break + } case 'Trigger On Event': { break } diff --git a/Spaces/StrategySpace.js b/Spaces/StrategySpace.js index 0a030a844..848785951 100644 --- a/Spaces/StrategySpace.js +++ b/Spaces/StrategySpace.js @@ -49,6 +49,7 @@ function newStrategySpace () { ['Manage Stage', 'video-player'], ['Close Stage', 'timeline'], ['Position Size', 'responsive'], + ['Position Rate', 'promotion'], ['Trigger On Event', 'startup'], ['Trigger Off Event', 'support'], ['Take Position Event', 'compass'], diff --git a/StrategySpace/Workspace/FunctionLibraries/AttachDetach.js b/StrategySpace/Workspace/FunctionLibraries/AttachDetach.js index 4272a110e..b486bd0ea 100644 --- a/StrategySpace/Workspace/FunctionLibraries/AttachDetach.js +++ b/StrategySpace/Workspace/FunctionLibraries/AttachDetach.js @@ -57,6 +57,11 @@ function newAttachDetach () { completeDetachment(node, rootNodes) return } + case 'Position Rate': { + node.payload.parentNode.positionRate = undefined + completeDetachment(node, rootNodes) + return + } case 'Trigger On Event': { node.payload.parentNode.triggerOn = undefined completeDetachment(node, rootNodes) @@ -205,6 +210,13 @@ function newAttachDetach () { completeAttachment(node, rootNodes) } break + case 'Position Rate': { + node.payload.parentNode = attachToNode + node.payload.chainParent = attachToNode + node.payload.parentNode.positionRate = node + completeAttachment(node, rootNodes) + } + break case 'Initial Definition': { node.payload.parentNode = attachToNode node.payload.chainParent = attachToNode diff --git a/StrategySpace/Workspace/FunctionLibraries/NodeChildren.js b/StrategySpace/Workspace/FunctionLibraries/NodeChildren.js index a6525663f..85d1664d9 100644 --- a/StrategySpace/Workspace/FunctionLibraries/NodeChildren.js +++ b/StrategySpace/Workspace/FunctionLibraries/NodeChildren.js @@ -35,6 +35,9 @@ function newNodeChildren () { case 'Position Size': { return countChildrenPositionSize(parentNode, childNode) } + case 'Position Rate': { + return countChildrenPositionSize(parentNode, childNode) + } case 'Initial Definition': { return countChildrenInitialDefinition(parentNode, childNode) } @@ -183,12 +186,6 @@ function newNodeChildren () { response.childIndex = response.childrenCount } } - if (parentNode.positionSize !== undefined) { - response.childrenCount++ - if (parentNode.positionSize.id === childNode.id) { - response.childIndex = response.childrenCount - } - } return response } @@ -248,11 +245,31 @@ function newNodeChildren () { return response } + function countChildrenPositionRate (parentNode, childNode) { + let response = { + childrenCount: 0, + childIndex: undefined + } + if (parentNode.formula !== undefined) { + response.childrenCount++ + if (parentNode.formula.id === childNode.id) { + response.childIndex = response.childrenCount + } + } + return response + } + function countChildrenInitialDefinition (parentNode, childNode) { let response = { childrenCount: 0, childIndex: undefined } + if (parentNode.positionSize !== undefined) { + response.childrenCount++ + if (parentNode.positionSize.id === childNode.id) { + response.childIndex = response.childrenCount + } + } if (parentNode.stopLoss !== undefined) { response.childrenCount++ if (parentNode.stopLoss.id === childNode.id) { @@ -265,6 +282,12 @@ function newNodeChildren () { response.childIndex = response.childrenCount } } + if (parentNode.positionRate !== undefined) { + response.childrenCount++ + if (parentNode.positionRate.id === childNode.id) { + response.childIndex = response.childrenCount + } + } return response } diff --git a/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js b/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js index 2fce8374a..51f9d84da 100644 --- a/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js +++ b/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js @@ -10,6 +10,7 @@ function newNodeDeleter () { deleteManageStage: deleteManageStage, deleteCloseStage: deleteCloseStage, deletePositionSize: deletePositionSize, + deletePositionRate: deletePositionRate, deleteInitialDefinition: deleteInitialDefinition, deleteEvent: deleteEvent, deleteManagedItem: deleteManagedItem, @@ -67,6 +68,10 @@ function newNodeDeleter () { deletePositionSize(rootNode, rootNodes) break } + case 'Position Rate': { + deletePositionRate(rootNode, rootNodes) + break + } case 'Initial Definition': { deleteInitialDefinition(rootNode, rootNodes) break @@ -213,9 +218,6 @@ function newNodeDeleter () { if (node.takePosition !== undefined) { deleteEvent(node.takePosition, rootNodes) } - if (node.positionSize !== undefined) { - deletePositionSize(node.positionSize, rootNodes) - } destroyPart(node) cleanNode(node) } @@ -276,6 +278,20 @@ function newNodeDeleter () { cleanNode(node) } + function deletePositionRate (node, rootNodes) { + let payload = node.payload + if (payload.parentNode !== undefined) { + payload.parentNode.positionRate = undefined + } else { + completeDeletion(node, rootNodes) + } + if (node.formula !== undefined) { + deleteFormula(node.formula, rootNodes) + } + destroyPart(node) + cleanNode(node) + } + function deleteInitialDefinition (node, rootNodes) { let payload = node.payload if (payload.parentNode !== undefined) { @@ -289,6 +305,12 @@ function newNodeDeleter () { if (node.takeProfit !== undefined) { deleteManagedItem(node.takeProfit, rootNodes) } + if (node.positionSize !== undefined) { + deletePositionSize(node.positionSize, rootNodes) + } + if (node.positionRate !== undefined) { + deletePositionSize(node.positionRate, rootNodes) + } destroyPart(node) cleanNode(node) } diff --git a/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js b/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js index 326121ce3..1e1620537 100644 --- a/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js +++ b/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js @@ -7,7 +7,6 @@ function newPartsFromNodes () { addMissingStages: addMissingStages, addMissingEvents: addMissingEvents, addMissingItems: addMissingItems, - addPositionSize: addPositionSize, addInitialDefinition: addInitialDefinition, addPhase: addPhase, addFormula: addFormula, @@ -112,6 +111,12 @@ function newPartsFromNodes () { if (node.takeProfit !== undefined) { createPartFromNode(node.takeProfit, node, node) } + if (node.positionSize !== undefined) { + createPartFromNode(node.positionSize, stage, stage) + } + if (node.positionRate !== undefined) { + createPartFromNode(node.positionRate, stage, stage) + } return } case 'Take Position Event': { @@ -148,6 +153,13 @@ function newPartsFromNodes () { } return } + case 'Position Rate': { + createPart('Position Rate', node.name, node, parentNode, chainParent, 'Position Rate') + if (node.formula !== undefined) { + createPartFromNode(node.formula, node, node) + } + return + } case 'Trigger Stage': { let stage = node createPart('Trigger Stage', stage.name, stage, parentNode, chainParent, 'Trigger Stage') @@ -161,9 +173,6 @@ function newPartsFromNodes () { if (node.takePosition !== undefined) { createPartFromNode(node.takePosition, stage, stage) } - if (node.positionSize !== undefined) { - createPartFromNode(node.positionSize, stage, stage) - } return } case 'Open Stage': { @@ -298,11 +307,12 @@ function newPartsFromNodes () { createPart('Trigger Off Event', '', strategy.triggerStage.triggerOff, strategy.triggerStage, strategy.triggerStage) createPart('Take Position Event', '', strategy.triggerStage.takePosition, strategy.triggerStage, strategy.triggerStage) createPart('Initial Definition', '', strategy.openStage.initialDefinition, strategy.openStage, strategy.openStage) + createPart('Position Size', '', strategy.openStage.initialDefinition.positionSize, strategy.openStage.initialDefinition, strategy.openStage.initialDefinition) + createPart('Position Rate', '', strategy.openStage.initialDefinition.positionRate, strategy.openStage.initialDefinition, strategy.openStage.initialDefinition) createPart('Stop', '', strategy.manageStage.stopLoss, strategy.manageStage, strategy.manageStage) createPart('Take Profit', '', strategy.manageStage.takeProfit, strategy.manageStage, strategy.manageStage) createPart('Stop', 'Initial Stop', strategy.openStage.initialDefinition.stopLoss, strategy.openStage.initialDefinition, strategy.openStage.initialDefinition) createPart('Take Profit', 'Initial Take Profit', strategy.openStage.initialDefinition.takeProfit, strategy.openStage.initialDefinition, strategy.openStage.initialDefinition) - createPart('Position Size', '', strategy.triggerStage.positionSize, strategy.triggerStage, strategy.triggerStage) createPart('Formula', '', strategy.triggerStage.positionSize.formula, strategy.triggerStage.positionSize, strategy.triggerStage.positionSize) } @@ -351,7 +361,6 @@ function newPartsFromNodes () { createPart('Trigger On Event', '', node.triggerStage.triggerOn, node.triggerStage, node.triggerStage) createPart('Trigger Off Event', '', node.triggerStage.triggerOff, node.triggerStage, node.triggerStage) createPart('Take Position Event', '', node.triggerStage.takePosition, node.triggerStage, node.triggerStage) - createPart('Position Size', '', node.triggerStage.positionSize, node.triggerStage, node.triggerStage) createPart('Formula', '', node.triggerStage.positionSize.formula, node.triggerStage.positionSize, node.triggerStage.positionSize) } if (node.openStage === undefined) { @@ -371,6 +380,8 @@ function newPartsFromNodes () { createPart('Initial Definition', '', node.openStage.initialDefinition, node.openStage, node.openStage) createPart('Stop', 'Initial Stop', node.openStage.initialDefinition.stopLoss, node.openStage.initialDefinition, node.openStage.initialDefinition) createPart('Take Profit', 'Initial Take Profit', node.openStage.initialDefinition.takeProfit, node.openStage.initialDefinition, node.openStage.initialDefinition) + createPart('Position Size', 'Position Size', node.openStage.initialDefinition.positionSize, node.openStage.initialDefinition, node.openStage.initialDefinition) + createPart('Position Rate', 'Position Rate', node.openStage.initialDefinition.positionRate, node.openStage.initialDefinition, node.openStage.initialDefinition) } if (node.manageStage === undefined) { node.manageStage = { @@ -411,19 +422,6 @@ function newPartsFromNodes () { } } - function addPositionSize (node) { - if (node.positionSize === undefined) { - node.positionSize = { - name: 'Position Size', - formula: { - code: DEFAULT_FORMULA_TEXT - } - } - createPart('Position Size', '', node.positionSize, node, node) - createPart('Formula', '', node.positionSize.formula, node.positionSize, node.positionSize) - } - } - function addMissingItems (node) { if (node.type === 'Initial Definition') { if (node.stopLoss === undefined) { @@ -440,6 +438,26 @@ function newPartsFromNodes () { } createPart('Take Profit', 'Initial Take Profit', node.takeProfit, node, node) } + if (node.positionSize === undefined) { + node.positionSize = { + name: 'Position Size', + formula: { + code: DEFAULT_FORMULA_TEXT + } + } + createPart('Position Size', '', node.positionSize, node, node) + createPart('Formula', '', node.positionSize.formula, node.positionSize, node.positionSize) + } + if (node.positionRate === undefined) { + node.positionRate = { + name: 'Position Rate', + formula: { + code: DEFAULT_FORMULA_TEXT + } + } + createPart('Position Rate', '', node.positionRate, node, node) + createPart('Formula', '', node.positionRate.formula, node.positionRate, node.positionRate) + } } else { if (node.stopLoss === undefined) { node.stopLoss = { diff --git a/StrategySpace/Workspace/FunctionLibraries/ProtocolNode.js b/StrategySpace/Workspace/FunctionLibraries/ProtocolNode.js index 481e51241..7cd069796 100644 --- a/StrategySpace/Workspace/FunctionLibraries/ProtocolNode.js +++ b/StrategySpace/Workspace/FunctionLibraries/ProtocolNode.js @@ -164,6 +164,15 @@ function newProtocolNode () { } return object } + case 'Position Rate': { + let object = { + type: node.type, + subType: node.subType, + name: node.name, + formula: getProtocolNode(node.formula) + } + return object + } case 'Trigger Stage': { let stage = { type: node.type, diff --git a/StrategySpace/Workspace/FunctionLibraries/StringifyNode.js b/StrategySpace/Workspace/FunctionLibraries/StringifyNode.js index 16638aedb..4cde2dfef 100644 --- a/StrategySpace/Workspace/FunctionLibraries/StringifyNode.js +++ b/StrategySpace/Workspace/FunctionLibraries/StringifyNode.js @@ -192,6 +192,17 @@ function newStringifyNode () { } return object } + case 'Position Rate': { + let object = { + id: node.id, + type: node.type, + subType: node.subType, + name: node.name, + formula: prepareForStringify(node.formula), + savedPayload: getSavedPayload(node) + } + return object + } case 'Trigger Stage': { let stage = { id: node.id, diff --git a/StrategySpace/Workspace/Workspace.js b/StrategySpace/Workspace/Workspace.js index 7c3463a6e..661f96ce0 100644 --- a/StrategySpace/Workspace/Workspace.js +++ b/StrategySpace/Workspace/Workspace.js @@ -212,11 +212,6 @@ function newWorkspace () { functionLibraryPartsFromNodes.addMissingEvents(payload.node) } break - case 'Add Position Size': - { - functionLibraryPartsFromNodes.addPositionSize(payload.node) - } - break case 'Add Missing Items': { functionLibraryPartsFromNodes.addMissingItems(payload.node) @@ -293,6 +288,10 @@ function newWorkspace () { functionLibraryNodeDeleter.deletePositionSize(payload.node, workspaceNode.rootNodes) break } + case 'Delete Position Rate': { + functionLibraryNodeDeleter.deletePositionSize(payload.node, workspaceNode.rootNodes) + break + } case 'Delete Initial Definition': { functionLibraryNodeDeleter.deleteInitialDefinition(payload.node, workspaceNode.rootNodes) break