diff --git a/FloatingSpace/StrategyPart.js b/FloatingSpace/StrategyPart.js index 095597d4c..cc3603f2a 100644 --- a/FloatingSpace/StrategyPart.js +++ b/FloatingSpace/StrategyPart.js @@ -24,7 +24,8 @@ function newStrategyPart () { getReadyToAttach: getReadyToAttach, showAvailabilityToAttach: showAvailabilityToAttach, highlight: highlight, - unHighlight: unHighlight, + setErrorMessage: setErrorMessage, + setValue: setValue, physics: physics, drawBackground: drawBackground, drawMiddleground: drawMiddleground, @@ -54,6 +55,12 @@ function newStrategyPart () { let isHighlighted let highlightCounter = 0 + + let hasError + let errorMessageCounter = 0 + + let hasValue + let valueCounter = 0 let runningCounter = 0 let previousDistance @@ -70,6 +77,9 @@ function newStrategyPart () { let isDragging = false let attachToNode + let errorMessage = '' + let formulaValue = 0 + return thisObject function finalize () { @@ -167,6 +177,8 @@ function newStrategyPart () { iconPhysics() runningPhisycs() highlightPhisycs() + errorMessagePhisycs() + valuePhisycs() detachingPhysics() attachingPhysics() } @@ -182,6 +194,14 @@ function newStrategyPart () { let compatibleType let compatibleSubType switch (thisObject.payload.node.type) { + case 'Parameters': + compatibleType = 'Trading System' + compatibleSubType = undefined + break + case 'Base Asset': + compatibleType = 'Parameters' + compatibleSubType = undefined + break case 'Strategy': compatibleType = 'Trading System' compatibleSubType = undefined @@ -202,6 +222,10 @@ function newStrategyPart () { compatibleType = 'Strategy' compatibleSubType = undefined break + case 'Position Size': + compatibleType = 'Trigger Stage' + compatibleSubType = undefined + break case 'Take Position Event': compatibleType = 'Trigger Stage' compatibleSubType = undefined @@ -231,7 +255,7 @@ function newStrategyPart () { compatibleSubType = undefined break case 'Formula': - compatibleType = 'Phase' + compatibleType = 'Base Asset' + '.' + 'Position Size' + '.' + 'Phase' compatibleSubType = undefined break case 'Next Phase Event': @@ -264,10 +288,13 @@ function newStrategyPart () { let nearbyNode = floatingObject.payload.node if (compatibleType.indexOf(nearbyNode.type) >= 0) { /* Discard objects with busy coonection ports */ + if (thisObject.payload.node.type === 'Parameters' && nearbyNode.parameters !== undefined) { continue } + if (thisObject.payload.node.type === 'Base Asset' && nearbyNode.baseAsset !== undefined) { continue } if (thisObject.payload.node.type === 'Trigger Stage' && nearbyNode.triggerStage !== undefined) { continue } if (thisObject.payload.node.type === 'Open Stage' && nearbyNode.openStage !== undefined) { continue } 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 === '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 } @@ -376,14 +403,41 @@ function newStrategyPart () { } } + function errorMessagePhisycs () { + errorMessageCounter-- + if (errorMessageCounter < 0) { + errorMessageCounter = 0 + hasError = false + } + } + + function valuePhisycs () { + valueCounter-- + if (valueCounter < 0) { + valueCounter = 0 + hasValue = false + } + } + function highlight () { isHighlighted = true highlightCounter = 30 } - function unHighlight () { - // isHighlighted = false - // highlightCounter = 0 + function setErrorMessage (message) { + if (message !== undefined) { + errorMessage = message + hasError = true + errorMessageCounter = 30 + } + } + + function setValue (value) { + if (value !== undefined) { + formulaValue = value + hasValue = true + valueCounter = 5 + } } function runningPhisycs () { @@ -462,6 +516,7 @@ function newStrategyPart () { function drawMiddleground () { if (thisObject.isOnFocus === false) { + drawValue() drawText() thisObject.partTitle.draw() } @@ -485,9 +540,6 @@ function newStrategyPart () { thisObject.codeEditor.drawForeground() } - drawText() - thisObject.partTitle.draw() - if (thisObject.codeEditor !== undefined) { if (thisObject.codeEditor.visible === false) { drawBodyAndPicture() @@ -503,6 +555,11 @@ function newStrategyPart () { thisObject.menu.drawForeground() } } + + drawErrorMessage() + drawValue() + drawText() + thisObject.partTitle.draw() } } @@ -593,6 +650,84 @@ function newStrategyPart () { } } + function drawErrorMessage () { + if (hasError === false) { return } + +/* Text Follows */ + let position = { + x: 0, + y: 0 + } + + position = thisObject.container.frame.frameThisPoint(position) + + let radius = thisObject.container.frame.radius + /* Label Text */ + let labelPoint + let fontSize = thisObject.payload.floatingObject.currentFontSize * 3 / 4 + let label + + if (radius > 6) { + const MAX_LABEL_LENGTH = 40 + + label = errorMessage + + if (label !== undefined) { + if (label.length > MAX_LABEL_LENGTH) { + label = label.substring(0, MAX_LABEL_LENGTH) + '...' + } + + labelPoint = { + x: position.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO - 5, + y: position.y + radius * 2 / 5 + fontSize * FONT_ASPECT_RATIO + 15 + } + + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)' + browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) + } + } + } + + function drawValue () { + if (hasValue === false) { return } + +/* Text Follows */ + let position = { + x: 0, + y: 0 + } + + position = thisObject.container.frame.frameThisPoint(position) + + let radius = thisObject.container.frame.radius + /* Label Text */ + let labelPoint + let fontSize = thisObject.payload.floatingObject.currentFontSize * 6 / 4 + let label + + if (radius > 6) { + const MAX_LABEL_LENGTH = 30 + + label = formulaValue.toFixed(2) + + if (label !== undefined) { + if (label.length > MAX_LABEL_LENGTH) { + label = label.substring(0, MAX_LABEL_LENGTH) + '...' + } + + labelPoint = { + x: position.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO - 5, + y: position.y + radius * 7 / 5 + fontSize * FONT_ASPECT_RATIO + 15 + } + + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TURQUOISE + ', 1)' + browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) + } + } + } + function addIndexNumber (label) { switch (thisObject.payload.node.type) { case 'Phase': { @@ -686,6 +821,17 @@ function newStrategyPart () { browserCanvasContext.fill() + if (thisObject.isOnFocus === true) { + VISIBLE_RADIUS = thisObject.container.frame.radius + browserCanvasContext.beginPath() + browserCanvasContext.arc(visiblePosition.x, visiblePosition.y, VISIBLE_RADIUS - 2, 0, Math.PI * 2, true) + browserCanvasContext.closePath() + + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.BLACK + ', 0.25)' + + browserCanvasContext.fill() + } + if (thisObject.isRunning === true) { VISIBLE_RADIUS = thisObject.container.frame.radius * 2 let OPACITY = runningCounter / 30 @@ -694,15 +840,30 @@ function newStrategyPart () { browserCanvasContext.arc(visiblePosition.x, visiblePosition.y, VISIBLE_RADIUS, 0, Math.PI * 2, true) browserCanvasContext.closePath() - browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + OPACITY + ')' + browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TURQUOISE + ', ' + OPACITY + ')' browserCanvasContext.lineWidth = 10 browserCanvasContext.setLineDash([4, 20]) browserCanvasContext.stroke() } + if (hasError === true) { + VISIBLE_RADIUS = thisObject.container.frame.radius * 1 + let OPACITY = errorMessageCounter / 30 + + browserCanvasContext.beginPath() + browserCanvasContext.arc(visiblePosition.x, visiblePosition.y, VISIBLE_RADIUS, 0, Math.PI * 2, true) + browserCanvasContext.closePath() + + browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + OPACITY + ')' + + browserCanvasContext.lineWidth = 10 + browserCanvasContext.setLineDash([19, 20]) + browserCanvasContext.stroke() + } + if (isHighlighted === true) { - VISIBLE_RADIUS = thisObject.container.frame.radius + VISIBLE_RADIUS = thisObject.container.frame.radius * 1 let OPACITY = highlightCounter / 30 browserCanvasContext.beginPath() @@ -751,11 +912,15 @@ function newStrategyPart () { if (icon !== undefined) { if (icon.canDrawIcon === true) { + let additionalImageSize = 0 + if (thisObject.isExecuting === true) { additionalImageSize = 20 } + let totalImageSize = additionalImageSize + thisObject.payload.floatingObject.currentImageSize + browserCanvasContext.drawImage( - icon, position.x - thisObject.payload.floatingObject.currentImageSize / 2, - position.y - thisObject.payload.floatingObject.currentImageSize / 2, - thisObject.payload.floatingObject.currentImageSize, - thisObject.payload.floatingObject.currentImageSize) + icon, position.x - totalImageSize / 2, + position.y - totalImageSize / 2, + totalImageSize, + totalImageSize) } } diff --git a/FloatingSpace/StrategyPartConstructor.js b/FloatingSpace/StrategyPartConstructor.js index a2eacd2be..12c5fd8ee 100644 --- a/FloatingSpace/StrategyPartConstructor.js +++ b/FloatingSpace/StrategyPartConstructor.js @@ -39,6 +39,10 @@ function newStrategyPartConstructor () { x: payload.node.savedPayload.position.x, y: payload.node.savedPayload.position.y } + + if (position.x === null) { position.x = spawnPosition.x } + if (position.y === null) { position.y = spawnPosition.y } + floatingObject.setPosition(position) payload.node.savedPayload.position = undefined if (payload.node.savedPayload.floatingObject.isPinned === true) { @@ -101,7 +105,7 @@ function newStrategyPartConstructor () { label: undefined, visible: false, iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOff: 'targeting', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -117,7 +121,7 @@ function newStrategyPartConstructor () { rawRadius: 8, targetRadius: 0, currentRadius: 0, - angle: -80 + angle: -70 }, { action: 'Save Trading System', @@ -144,7 +148,7 @@ function newStrategyPartConstructor () { rawRadius: 8, targetRadius: 0, currentRadius: 0, - angle: 0 + angle: -10 }, { action: 'New Strategy', @@ -157,6 +161,19 @@ function newStrategyPartConstructor () { rawRadius: 8, targetRadius: 0, currentRadius: 0, + angle: +10 + }, + { + action: 'Add Parameters', + actionFunction: payload.onMenuItemClick, + label: 'Add Parameters', + visible: false, + iconPathOn: 'quality', + iconPathOff: 'quality', + relatedStrategyPart: 'Parameters', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, angle: 40 }, { @@ -169,7 +186,144 @@ function newStrategyPartConstructor () { rawRadius: 8, targetRadius: 0, currentRadius: 0, - angle: 80 + angle: 70 + }] + break + } + case 'Parameters': { + 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: '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 Parameters', + actionFunction: payload.onMenuItemClick, + label: 'Delete Trading System', + visible: false, + iconPathOn: 'trash', + iconPathOff: 'trash', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -40 + }, + { + action: 'Add Missing Parameters', + actionFunction: payload.onMenuItemClick, + label: 'Add Missing Params', + visible: false, + iconPathOn: 'settings', + iconPathOff: 'settings', + 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 'Base Asset': { + 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: '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 Base Asset', + actionFunction: payload.onMenuItemClick, + label: 'Delete Base Asset', + 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 } @@ -196,8 +350,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -264,8 +418,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -281,7 +435,20 @@ function newStrategyPartConstructor () { rawRadius: 8, targetRadius: 0, currentRadius: 0, - angle: -40 + 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 }, { action: 'Delete Trigger Stage', @@ -293,7 +460,7 @@ function newStrategyPartConstructor () { rawRadius: 8, targetRadius: 0, currentRadius: 0, - angle: 0 + angle: 20 }, { action: 'Download', @@ -305,7 +472,7 @@ function newStrategyPartConstructor () { rawRadius: 8, targetRadius: 0, currentRadius: 0, - angle: 40 + angle: 60 }] break } @@ -332,8 +499,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -400,8 +567,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -468,8 +635,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -501,6 +668,75 @@ function newStrategyPartConstructor () { }] break } + case 'Position Size': { + 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: '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 Size', + actionFunction: payload.onMenuItemClick, + label: 'Delete Trading System', + 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 'Trigger On Event': { menuItemsInitialValues = [ { @@ -524,8 +760,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -593,8 +829,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -662,8 +898,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -731,8 +967,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -799,8 +1035,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -868,8 +1104,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -937,8 +1173,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -949,8 +1185,8 @@ function newStrategyPartConstructor () { actionFunction: payload.onMenuItemClick, label: 'Add Formula', visible: false, - iconPathOn: 'schedule', - iconPathOff: 'schedule', + iconPathOn: 'pipette', + iconPathOff: 'pipette', relatedStrategyPart: 'Formula', rawRadius: 8, targetRadius: 0, @@ -1024,8 +1260,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -1093,8 +1329,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -1162,8 +1398,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -1231,8 +1467,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -1305,8 +1541,8 @@ function newStrategyPartConstructor () { currentStatus: true, label: undefined, visible: false, - iconPathOn: 'broken-link', - iconPathOff: 'security', + iconPathOn: 'targeting', + iconPathOff: 'broken-link', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -1368,6 +1604,14 @@ function newStrategyPartConstructor () { level_0() break } + case 'Parameters': { + level_3() + break + } + case 'Base Asset': { + level_3() + break + } case 'Strategy': { level_1() break @@ -1388,6 +1632,10 @@ function newStrategyPartConstructor () { level_2() break } + case 'Position Size': { + level_3() + break + } case 'Trigger On Event': { level_3() break @@ -1429,11 +1677,11 @@ function newStrategyPartConstructor () { break } case 'Condition': { - level_6() + level_5() break } case 'Code': { - level_6() + level_5() break } default: { @@ -1482,7 +1730,7 @@ function newStrategyPartConstructor () { floatingObject.targetFriction = FRICTION floatingObject.friction = INITIAL_FRICTION - floatingObject.initializeMass(10) + floatingObject.initializeMass(20) floatingObject.initializeRadius(35) floatingObject.initializeImageSize(60) floatingObject.initializeFontSize(10) @@ -1494,7 +1742,7 @@ function newStrategyPartConstructor () { floatingObject.targetFriction = FRICTION floatingObject.friction = INITIAL_FRICTION - floatingObject.initializeMass(10) + floatingObject.initializeMass(20) floatingObject.initializeRadius(30) floatingObject.initializeImageSize(50) floatingObject.initializeFontSize(10) @@ -1506,7 +1754,7 @@ function newStrategyPartConstructor () { floatingObject.targetFriction = FRICTION floatingObject.friction = INITIAL_FRICTION - floatingObject.initializeMass(10) + floatingObject.initializeMass(20) floatingObject.initializeRadius(25) floatingObject.initializeImageSize(40) floatingObject.initializeFontSize(10) @@ -1517,7 +1765,7 @@ function newStrategyPartConstructor () { floatingObject.targetFriction = FRICTION floatingObject.friction = INITIAL_FRICTION - floatingObject.initializeMass(10) + floatingObject.initializeMass(20) floatingObject.initializeRadius(20) floatingObject.initializeImageSize(30) floatingObject.initializeFontSize(10) diff --git a/FloatingSpace/StrategyPartTitle.js b/FloatingSpace/StrategyPartTitle.js index 496eb5aef..d00a9eccd 100644 --- a/FloatingSpace/StrategyPartTitle.js +++ b/FloatingSpace/StrategyPartTitle.js @@ -52,6 +52,12 @@ function newStrategyPartTitle () { thisObject.allwaysVisible = true break } + case 'Parameters': { + break + } + case 'Base Asset': { + break + } case 'Strategy': { thisObject.allwaysVisible = true break @@ -68,6 +74,9 @@ function newStrategyPartTitle () { case 'Close Stage': { break } + case 'Position Size': { + break + } case 'Trigger On Event': { break } @@ -279,7 +288,7 @@ function newStrategyPartTitle () { function trimTitle (title) { if (title === undefined) { return } - const MAX_LABEL_LENGTH = 35 + const MAX_LABEL_LENGTH = 30 if (title.length > MAX_LABEL_LENGTH) { title = title.substring(0, MAX_LABEL_LENGTH) + '...' } diff --git a/Globals.js b/Globals.js index ada8e2e55..6c1c265f8 100644 --- a/Globals.js +++ b/Globals.js @@ -189,6 +189,8 @@ const PRODUCT_CARD_STATUS = { OFF: 'off' }; +let spawnPosition // this is used in several places. + /* Here we list the valid Time Periods: */ const PERIOD_24_HS = "24-hs"; diff --git a/Panels/ProductsPanel.js b/Panels/ProductsPanel.js index 8ba4c18da..51bf2e5e7 100644 --- a/Panels/ProductsPanel.js +++ b/Panels/ProductsPanel.js @@ -60,7 +60,7 @@ function newProductsPanel () { /* First thing is to build the thisObject.productCards array */ - let ecosystem = JSON.parse(window.localStorage.getItem('ecosystem')) + let ecosystem = JSON.parse(window.localStorage.getItem('TEST_ecosystem')) for (let i = 0; i < ecosystem.devTeams.length; i++) { let devTeam = ecosystem.devTeams[i] diff --git a/Spaces/StrategySpace.js b/Spaces/StrategySpace.js index d99d48d32..01e7bc5df 100644 --- a/Spaces/StrategySpace.js +++ b/Spaces/StrategySpace.js @@ -41,11 +41,14 @@ function newStrategySpace () { function buildIconByPartTypeMap () { const relationshipArray = [ ['Trading System', 'analysis'], + ['Parameters', 'settings'], + ['Base Asset', 'sitemap'], ['Strategy', 'quality'], ['Trigger Stage', 'chronometer'], ['Open Stage', 'photo-camera'], ['Manage Stage', 'video-player'], ['Close Stage', 'timeline'], + ['Position Size', 'responsive'], ['Trigger On Event', 'startup'], ['Trigger Off Event', 'support'], ['Take Position Event', 'compass'], diff --git a/StrategySpace/ConstDeleteStrategy.js b/StrategySpace/ConstDeleteStrategy.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/StrategySpace/ConstGetStrategies.js b/StrategySpace/ConstGetStrategies.js deleted file mode 100644 index b3b9c2c09..000000000 --- a/StrategySpace/ConstGetStrategies.js +++ /dev/null @@ -1,87 +0,0 @@ -const GRAPHQL_QUERY_GET_STRATEGIES = Apollo.gql` - query($fbSlug: String!){ - - strategizer_StrategyByFb(fbSlug: $fbSlug){ - id - subStrategies(activeOnly: true){ - name - active - triggerOn{ - situations{ - name - conditions{ - name - code - } - } - } - triggerOff{ - situations{ - name - conditions{ - name - code - } - } - } - takePosition{ - situations{ - name - conditions{ - name - code - } - } - } - buyPoint{ - situations{ - name - conditions{ - name - code - } - } - } - stopLoss{ - phases{ - name - code - situations{ - name - conditions{ - name - code - } - } - } - } - takeProfit{ - phases{ - name - code - situations{ - name - conditions{ - name - code - } - } - } - } - sellOrder{ - phases{ - name - code - situations{ - name - conditions{ - name - code - } - } - } - } - } - } - } - ` diff --git a/StrategySpace/ConstNewStrategy.js b/StrategySpace/ConstNewStrategy.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/StrategySpace/ConstUpdateStrategy.js b/StrategySpace/ConstUpdateStrategy.js deleted file mode 100644 index d84ce30cf..000000000 --- a/StrategySpace/ConstUpdateStrategy.js +++ /dev/null @@ -1,7 +0,0 @@ -const GRAPHQL_MUTATION_UPDATE_STRATEGIES = Apollo.gql` - mutation strategizer_EditStrategy($id: ID!, $strategy: strategizer_StrategyInput!) { - strategizer_EditStrategy(id: $id, strategy: $strategy) { - id - } - } -` diff --git a/StrategySpace/StrategizerGateway.js b/StrategySpace/StrategizerGateway.js index 222449458..9a314ba3e 100644 --- a/StrategySpace/StrategizerGateway.js +++ b/StrategySpace/StrategizerGateway.js @@ -1,353 +1,187 @@ - -function newStrategizerGateway () { - const MODULE_NAME = 'Strategizer Gateway' - const ERROR_LOG = true - const logger = newWebDebugLog() - logger.fileName = MODULE_NAME - - let thisObject = { - strategizerData: undefined, - container: undefined, - loadFromStrategyzer: loadFromStrategyzer, - saveToStrategyzer: saveToStrategyzer, - draw: draw, - getContainer: getContainer, - initialize: initialize - } - - let colletionItems = [] - - thisObject.container = newContainer() - thisObject.container.name = MODULE_NAME - thisObject.container.initialize() - - thisObject.container.frame.width = 0 - thisObject.container.frame.height = 0 - - thisObject.container.frame.position.x = 0 - thisObject.container.frame.position.y = 0 - - thisObject.container.isDraggeable = false - thisObject.container.isClickeable = false - - return thisObject - - function initialize () { - - } - - async function saveToStrategyzer () { - try { - const accessToken = window.localStorage.getItem(LOGGED_IN_ACCESS_TOKEN_LOCAL_STORAGE_KEY) - - let user = window.localStorage.getItem(LOGGED_IN_USER_LOCAL_STORAGE_KEY) - if (user === null) { - if (ERROR_LOG === true) { logger.write('[ERROR] saveToStrategyzer -> Can not save because user is not logged in. ') } - return - } - - user = JSON.parse(user) - - const authId = user.authId - - const apolloClient = new Apollo.lib.ApolloClient({ - networkInterface: Apollo.lib.createNetworkInterface({ - uri: window.canvasApp.graphQL.masterAppApiUrl, - transportBatching: true - }), - connectToDevTools: true - }) - - /* Updating all Strategies */ - - const networkInterface = Apollo.lib.createNetworkInterface({ - uri: window.canvasApp.graphQL.masterAppApiUrl - }) - - networkInterface.use([{ - applyMiddleware (req, next) { - req.options.headers = { - authorization: `Bearer ${accessToken}` - } - next() + +function newStrategizerGateway () { + const MODULE_NAME = 'Strategizer Gateway' + const ERROR_LOG = true + const logger = newWebDebugLog() + logger.fileName = MODULE_NAME + + let thisObject = { + strategizerData: undefined, + container: undefined, + loadFromStrategyzer: loadFromStrategyzer, + saveToStrategyzer: saveToStrategyzer, + draw: draw, + getContainer: getContainer, + initialize: initialize + } + + let colletionItems = [] + + thisObject.container = newContainer() + thisObject.container.name = MODULE_NAME + thisObject.container.initialize() + + thisObject.container.frame.width = 0 + thisObject.container.frame.height = 0 + + thisObject.container.frame.position.x = 0 + thisObject.container.frame.position.y = 0 + + thisObject.container.isDraggeable = false + thisObject.container.isClickeable = false + + return thisObject + + function initialize () { + + } + + async function saveToStrategyzer () { + try { + const accessToken = window.localStorage.getItem(LOGGED_IN_ACCESS_TOKEN_LOCAL_STORAGE_KEY) + + let user = window.localStorage.getItem(LOGGED_IN_USER_LOCAL_STORAGE_KEY) + if (user === null) { + if (ERROR_LOG === true) { logger.write('[ERROR] saveToStrategyzer -> Can not save because user is not logged in. ') } + return + } + + user = JSON.parse(user) + let fbSlug = 'simulator' + '-' + user.alias + + /* See if we need to update or create a new record at the strategizer */ + + let tradingSystem = canvas.strategySpace.workspace.getProtocolTradingSystem() + let idAtStrategizer = canvas.strategySpace.workspace.idAtStrategizer + + if (idAtStrategizer === undefined) { + let response = await axios({ + url: window.canvasApp.graphQL.masterAppApiUrl, + method: 'post', + data: { + query: ` + mutation strategizer_CreateTradingSystem + ( + $fbSlug: String!, $data: strategizer_JSON! + ) + { + strategizer_CreateTradingSystem(fbSlug: $fbSlug, tradingSystem: { data: $data }) + { + id + } + } + `, + variables: { + fbSlug: fbSlug, + data: tradingSystem + } + }, + headers: { + authorization: 'Bearer ' + accessToken + } + }) + + if (response.data.errors) { + console.log('Error getting events: ' + JSON.stringify(response.data.errors)) + throw 'Error getting events: ' + JSON.stringify(response.data.errors) + } else { + canvas.strategySpace.workspace.idAtStrategizer = response.data.data.strategizer_CreateTradingSystem.id } - }]) - - let tradingSystem = canvas.strategySpace.workspace.tradingSystem - let idAtStrategizer = canvas.strategySpace.workspace.idAtStrategizer - let dataToSave = buildGraphQLDataToSave(tradingSystem) - - const updateStrategies = () => { - return new Promise((resolve, reject) => { - apolloClient.mutate({ - mutation: GRAPHQL_MUTATION_UPDATE_STRATEGIES, - variables: { - id: idAtStrategizer, - strategy: dataToSave.strategy - } - }) - .then(response => { - resolve(true) - }) - .catch(err => { - if (ERROR_LOG === true) { logger.write('[ERROR] saveToStrategyzer -> ApolloClient error updating user strategies -> err = ' + err.stack) } - reject(err) - }) + } else { + const graphQLServer = await axios({ + url: window.canvasApp.graphQL.masterAppApiUrl, + method: 'post', + data: { + query: ` + mutation strategizer_EditTradingSystem + ( + $id: ID!, $data: strategizer_JSON! + ) + { + strategizer_EditTradingSystem(id: $id, tradingSystem: { data: $data }) + { + id + } + } + `, + variables: { + id: idAtStrategizer, + data: tradingSystem + } + }, + headers: { + authorization: 'Bearer ' + accessToken + } }) + } + + return true + } catch (err) { + if (ERROR_LOG === true) { logger.write('[ERROR] saveToStrategyzer -> err = ' + err.stack) } + } + } + + async function loadFromStrategyzer () { + try { + const accessToken = window.localStorage.getItem(LOGGED_IN_ACCESS_TOKEN_LOCAL_STORAGE_KEY) + + let user = window.localStorage.getItem(LOGGED_IN_USER_LOCAL_STORAGE_KEY) + if (user === null) { + // if there is no user that means that we are logged off, which means this object can not be used. + return + } + + user = JSON.parse(user) + let fbSlug = 'simulator' + '-' + user.alias + + let response = await axios({ + url: window.canvasApp.graphQL.masterAppApiUrl, + method: 'post', + data: { + query: + ` + query($fbSlug: String!){ + strategizer_TradingSystemByFb(fbSlug: $fbSlug){ + id + fbSlug + data + } + } + `, + variables: { + fbSlug: fbSlug + } + }, + headers: { + authorization: 'Bearer ' + accessToken + } + }) + + if (response.data.errors) { + if (response.data.errors[0] === 'Ressource not found : None of the tradingSystem are linked to that fbSlug') { + return false + } else { + logger.write('[ERROR] Error while getting Trading System from Strategizer: ' + JSON.stringify(response.data.errors)) + return false + } + } else { + window.localStorage.setItem('userStrategies', JSON.stringify(response.data.data.strategizer_TradingSystemByFb.data)) + thisObject.strategizerData = JSON.parse(JSON.stringify(response.data.data.strategizer_TradingSystemByFb.data)) + canvas.strategySpace.workspace.idAtStrategizer = response.data.data.strategizer_TradingSystemByFb.id + return true } - - let result = await updateStrategies() - - return result - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] saveToStrategyzer -> err = ' + err.stack) } - } - } - - function buildGraphQLDataToSave (tradingSystem) { - let graphQL_Mutation = '' - - let dataToSave = { - strategy: { - subStrategies: [] - } - } - - for (m = 0; m < tradingSystem.strategies.length; m++) { - let strategizerGatewayStrategy = tradingSystem.strategies[m] - let strategy = { - name: strategizerGatewayStrategy.name, - active: strategizerGatewayStrategy.active, - triggerOn: { - situations: [] - }, - triggerOff: { - situations: [] - }, - takePosition: { - situations: [] - }, - stopLoss: { - phases: [] - }, - takeProfit: { - phases: [] - } - } - - for (let k = 0; k < strategizerGatewayStrategy.triggerOn.situations.length; k++) { - let strategizerGatewaySituation = strategizerGatewayStrategy.triggerOn.situations[k] - let situation = { - name: strategizerGatewaySituation.name, - conditions: [] - } - - for (let m = 0; m < strategizerGatewaySituation.conditions.length; m++) { - let strategizerGatewayCondition = strategizerGatewaySituation.conditions[m] - let condition = { - name: strategizerGatewayCondition.name, - code: strategizerGatewayCondition.code - } - situation.conditions.push(condition) - } - strategy.triggerOn.situations.push(situation) - } - - for (let k = 0; k < strategizerGatewayStrategy.triggerOff.situations.length; k++) { - let strategizerGatewaySituation = strategizerGatewayStrategy.triggerOff.situations[k] - let situation = { - name: strategizerGatewaySituation.name, - conditions: [] - } - - for (let m = 0; m < strategizerGatewaySituation.conditions.length; m++) { - let strategizerGatewayCondition = strategizerGatewaySituation.conditions[m] - let condition = { - name: strategizerGatewayCondition.name, - code: strategizerGatewayCondition.code - } - situation.conditions.push(condition) - } - strategy.triggerOff.situations.push(situation) - } - - for (let k = 0; k < strategizerGatewayStrategy.takePosition.situations.length; k++) { - let strategizerGatewaySituation = strategizerGatewayStrategy.takePosition.situations[k] - let situation = { - name: strategizerGatewaySituation.name, - conditions: [] - } - - for (let m = 0; m < strategizerGatewaySituation.conditions.length; m++) { - let strategizerGatewayCondition = strategizerGatewaySituation.conditions[m] - let condition = { - name: strategizerGatewayCondition.name, - code: strategizerGatewayCondition.code - } - situation.conditions.push(condition) - } - strategy.takePosition.situations.push(situation) - } - - for (let p = 0; p < strategizerGatewayStrategy.stopLoss.phases.length; p++) { - let strategizerGatewayPhase = strategizerGatewayStrategy.stopLoss.phases[p] - let phase = { - name: strategizerGatewayPhase.name, - code: strategizerGatewayPhase.code, - situations: [] - } - - for (let k = 0; k < strategizerGatewayPhase.situations.length; k++) { - let strategizerGatewaySituation = strategizerGatewayPhase.situations[k] - let situation = { - name: strategizerGatewaySituation.name, - conditions: [] - } - - for (let m = 0; m < strategizerGatewaySituation.conditions.length; m++) { - let strategizerGatewayCondition = strategizerGatewaySituation.conditions[m] - let condition = { - name: strategizerGatewayCondition.name, - code: strategizerGatewayCondition.code - } - situation.conditions.push(condition) - } - phase.situations.push(situation) - } - strategy.stopLoss.phases.push(phase) - } - - for (let p = 0; p < strategizerGatewayStrategy.takeProfit.phases.length; p++) { - let strategizerGatewayPhase = strategizerGatewayStrategy.takeProfit.phases[p] - let phase = { - name: strategizerGatewayPhase.name, - code: strategizerGatewayPhase.code, - situations: [] - } - - for (let k = 0; k < strategizerGatewayPhase.situations.length; k++) { - let strategizerGatewaySituation = strategizerGatewayPhase.situations[k] - let situation = { - name: strategizerGatewaySituation.name, - conditions: [] - } - - for (let m = 0; m < strategizerGatewaySituation.conditions.length; m++) { - let strategizerGatewayCondition = strategizerGatewaySituation.conditions[m] - let condition = { - name: strategizerGatewayCondition.name, - code: strategizerGatewayCondition.code - } - situation.conditions.push(condition) - } - phase.situations.push(situation) - } - strategy.takeProfit.phases.push(phase) - } - dataToSave.strategy.subStrategies.push(strategy) - } - - return dataToSave - } - - async function loadFromStrategyzer () { - try { - const accessToken = window.localStorage.getItem(LOGGED_IN_ACCESS_TOKEN_LOCAL_STORAGE_KEY) - - let user = window.localStorage.getItem(LOGGED_IN_USER_LOCAL_STORAGE_KEY) - if (user === null) { - // if there is no user that means that we are logged off, which means this object can not be used. - return - } - - user = JSON.parse(user) - - const authId = user.authId - - const apolloClient = new Apollo.lib.ApolloClient({ - networkInterface: Apollo.lib.createNetworkInterface({ - uri: window.canvasApp.graphQL.masterAppApiUrl, - transportBatching: true - }), - connectToDevTools: true - }) - - /* Getting the FB that own the Strategies */ - - let teamtradingSystemSimulationFB = '' - let ecosystem = JSON.parse(window.localStorage.getItem('ecosystem')) - let teams = ecosystem.devTeams - for (let i = 0; i < teams.length; i++) { - let team = teams[i] - for (let j = 0; j < team.bots.length; j++) { - let bot = team.bots[j] - if (bot.codeName.indexOf('simulator') >= 0) { - teamtradingSystemSimulationFB = bot.codeName - } - } - } - - if (teamtradingSystemSimulationFB === '') { - if (ERROR_LOG === true) { logger.write('[ERROR] loadFromStrategyzer -> no simulation FB found at user teams. ') } - return - } - /* Getting all Strategies */ - - const networkInterface = Apollo.lib.createNetworkInterface({ - uri: window.canvasApp.graphQL.masterAppApiUrl - }) - - networkInterface.use([{ - applyMiddleware (req, next) { - req.options.headers = { - authorization: `Bearer ${accessToken}` - } - next() - } - }]) - - const getStrategies = () => { - return new Promise((resolve, reject) => { - apolloClient.query({ - query: GRAPHQL_QUERY_GET_STRATEGIES, - variables: { fbSlug: teamtradingSystemSimulationFB} - }) - .then(response => { - window.localStorage.setItem('userStrategies', JSON.stringify(response.data.strategizer_StrategyByFb)) - thisObject.strategizerData = JSON.parse(JSON.stringify(response.data.strategizer_StrategyByFb)) - - resolve({ strategies: response.data.strategizer_StrategyByFb.subStrategies}) - }) - .catch(err => { - if (ERROR_LOG === true) { logger.write('[ERROR] loadFromStrategyzer -> ApolloClient error getting user strategies -> err = ' + err.stack) } - reject(err) - }) - }) - } - - // To avoid race conditions, add asynchronous fetches to array - let fetchDataPromises = [] - - fetchDataPromises.push(getStrategies()) - - // When all asynchronous fetches resolve, authenticate user or throw error. - await Promise.all(fetchDataPromises).then(result => { - - }, err => { - if (ERROR_LOG === true) { logger.write('[ERROR] loadFromStrategyzer -> GraphQL Fetch Error -> err = ' + err.stack) } - }) - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] loadFromStrategyzer -> err = ' + err.stack) } - } - } - - function getContainer (point) { - let container - - return undefined - } - - function draw () { - - } -} + } catch (err) { + if (ERROR_LOG === true) { logger.write('[ERROR] loadFromStrategyzer -> err = ' + err.stack) } + } + } + + function getContainer (point) { + let container + + return undefined + } + + function draw () { + + } +} diff --git a/StrategySpace/Workspace/FunctionLibraries/AttachDetach.js b/StrategySpace/Workspace/FunctionLibraries/AttachDetach.js index 750290153..4272a110e 100644 --- a/StrategySpace/Workspace/FunctionLibraries/AttachDetach.js +++ b/StrategySpace/Workspace/FunctionLibraries/AttachDetach.js @@ -11,6 +11,16 @@ function newAttachDetach () { case 'Trading System': { return } + case 'Parameters': { + node.payload.parentNode.parameters = undefined + completeDetachment(node, rootNodes) + return + } + case 'Base Asset': { + node.payload.parentNode.baseAsset = undefined + completeDetachment(node, rootNodes) + return + } case 'Strategy': { let payload = node.payload for (let i = 0; i < payload.parentNode.strategies.length; i++) { @@ -42,6 +52,11 @@ function newAttachDetach () { completeDetachment(node, rootNodes) return } + case 'Position Size': { + node.payload.parentNode.positionSize = undefined + completeDetachment(node, rootNodes) + return + } case 'Trigger On Event': { node.payload.parentNode.triggerOn = undefined completeDetachment(node, rootNodes) @@ -134,6 +149,20 @@ function newAttachDetach () { function attachNode (node, attachToNode, rootNodes) { switch (node.type) { + case 'Parameters': { + node.payload.parentNode = attachToNode + node.payload.chainParent = attachToNode + node.payload.parentNode.parameters = node + completeAttachment(node, rootNodes) + } + break + case 'Base Asset': { + node.payload.parentNode = attachToNode + node.payload.chainParent = attachToNode + node.payload.parentNode.baseAsset = node + completeAttachment(node, rootNodes) + } + break case 'Strategy': { node.payload.parentNode = attachToNode node.payload.chainParent = attachToNode @@ -169,6 +198,13 @@ function newAttachDetach () { completeAttachment(node, rootNodes) } break + case 'Position Size': { + node.payload.parentNode = attachToNode + node.payload.chainParent = attachToNode + node.payload.parentNode.positionSize = node + completeAttachment(node, rootNodes) + } + break case 'Initial Definition': { node.payload.parentNode = attachToNode node.payload.chainParent = attachToNode diff --git a/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js b/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js index 9ed435656..ab64cbbe5 100644 --- a/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js +++ b/StrategySpace/Workspace/FunctionLibraries/NodeDeleter.js @@ -1,11 +1,14 @@ function newNodeDeleter () { thisObject = { deleteTradingSystem: deleteTradingSystem, + deleteParameters: deleteParameters, + deleteBaseAsset: deleteBaseAsset, deleteStrategy: deleteStrategy, deleteTriggerStage: deleteTriggerStage, deleteOpenStage: deleteOpenStage, deleteManageStage: deleteManageStage, deleteCloseStage: deleteCloseStage, + deletePositionSize: deletePositionSize, deleteInitialDefinition: deleteInitialDefinition, deleteEvent: deleteEvent, deleteManagedItem: deleteManagedItem, @@ -38,7 +41,7 @@ function newNodeDeleter () { } while (node.strategies.length > 0) { - deleteStrategy(node.strategies[0]) + deleteStrategy(node.strategies[0], rootNodes) } completeDeletion(node, rootNodes) @@ -46,6 +49,34 @@ function newNodeDeleter () { cleanNode(node) } + function deleteParameters (node, rootNodes) { + let payload = node.payload + if (payload.parentNode !== undefined) { + payload.parentNode.parameters = undefined + } else { + completeDeletion(node, rootNodes) + } + if (node.baseAsset !== undefined) { + deleteBaseAsset(node.baseAsset, rootNodes) + } + destroyPart(node) + cleanNode(node) + } + + function deleteBaseAsset (node, rootNodes) { + let payload = node.payload + if (payload.parentNode !== undefined) { + payload.parentNode.baseAsset = undefined + } else { + completeDeletion(node, rootNodes) + } + if (node.formula !== undefined) { + deleteFormula(node.formula, rootNodes) + } + destroyPart(node) + cleanNode(node) + } + function deleteStrategy (node, rootNodes) { let payload = node.payload if (payload.parentNode !== undefined) { @@ -59,16 +90,16 @@ function newNodeDeleter () { completeDeletion(node, rootNodes) } if (node.triggerStage !== undefined) { - deleteTriggerStage(node.triggerStage) + deleteTriggerStage(node.triggerStage, rootNodes) } if (node.openStage !== undefined) { - deleteOpenStage(node.openStage) + deleteOpenStage(node.openStage, rootNodes) } if (node.manageStage !== undefined) { - deleteManageStage(node.manageStage) + deleteManageStage(node.manageStage, rootNodes) } if (node.closeStage !== undefined) { - deleteCloseStage(node.closeStage) + deleteCloseStage(node.closeStage, rootNodes) } destroyPart(node) cleanNode(node) @@ -82,13 +113,13 @@ function newNodeDeleter () { completeDeletion(node, rootNodes) } if (node.triggerOn !== undefined) { - deleteEvent(node.triggerOn) + deleteEvent(node.triggerOn, rootNodes) } if (node.triggerOff !== undefined) { - deleteEvent(node.triggerOff) + deleteEvent(node.triggerOff, rootNodes) } if (node.takePosition !== undefined) { - deleteEvent(node.takePosition) + deleteEvent(node.takePosition, rootNodes) } destroyPart(node) cleanNode(node) @@ -102,7 +133,7 @@ function newNodeDeleter () { completeDeletion(node, rootNodes) } if (node.initialDefinition !== undefined) { - deleteInitialDefinition(node.initialDefinition) + deleteInitialDefinition(node.initialDefinition, rootNodes) } destroyPart(node) cleanNode(node) @@ -116,10 +147,10 @@ function newNodeDeleter () { completeDeletion(node, rootNodes) } if (node.stopLoss !== undefined) { - deleteManagedItem(node.stopLoss) + deleteManagedItem(node.stopLoss, rootNodes) } if (node.takeProfit !== undefined) { - deleteManagedItem(node.takeProfit) + deleteManagedItem(node.takeProfit, rootNodes) } destroyPart(node) cleanNode(node) @@ -136,6 +167,20 @@ function newNodeDeleter () { cleanNode(node) } + function deletePositionSize (node, rootNodes) { + let payload = node.payload + if (payload.parentNode !== undefined) { + payload.parentNode.positionSize = 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) { @@ -144,10 +189,10 @@ function newNodeDeleter () { completeDeletion(node, rootNodes) } if (node.stopLoss !== undefined) { - deleteManagedItem(node.stopLoss) + deleteManagedItem(node.stopLoss, rootNodes) } if (node.takeProfit !== undefined) { - deleteManagedItem(node.takeProfit) + deleteManagedItem(node.takeProfit, rootNodes) } destroyPart(node) cleanNode(node) @@ -179,7 +224,7 @@ function newNodeDeleter () { } while (node.situations.length > 0) { - deleteSituation(node.situations[0]) + deleteSituation(node.situations[0], rootNodes) } destroyPart(node) cleanNode(node) @@ -258,7 +303,7 @@ function newNodeDeleter () { if (situation.id === node.id) { while (situation.conditions.length > 0) { let condition = situation.conditions[0] - deleteCondition(condition) + deleteCondition(condition, rootNodes) } situation.conditions = [] payload.parentNode.situations.splice(j, 1) diff --git a/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js b/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js index b623c2b17..742db41ad 100644 --- a/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js +++ b/StrategySpace/Workspace/FunctionLibraries/PartsFromNodes.js @@ -2,9 +2,12 @@ function newPartsFromNodes () { thisObject = { createPartFromNode: createPartFromNode, newStrategy: newStrategy, + addParameters: addParameters, + addMissingParameters: addMissingParameters, addMissingStages: addMissingStages, addMissingEvents: addMissingEvents, addMissingItems: addMissingItems, + addPositionSize: addPositionSize, addInitialDefinition: addInitialDefinition, addPhase: addPhase, addFormula: addFormula, @@ -138,6 +141,13 @@ function newPartsFromNodes () { } return } + case 'Position Size': { + createPart('Position Size', node.name, node, parentNode, chainParent, 'Position Size') + 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') @@ -151,6 +161,9 @@ function newPartsFromNodes () { if (node.takePosition !== undefined) { createPartFromNode(node.takePosition, stage, stage) } + if (node.positionSize !== undefined) { + createPartFromNode(node.positionSize, stage, stage) + } return } case 'Open Stage': { @@ -196,6 +209,20 @@ function newPartsFromNodes () { } return } + case 'Base Asset': { + createPart('Base Asset', node.name, node, parentNode, chainParent, 'Base Asset') + if (node.formula !== undefined) { + createPartFromNode(node.formula, node, node) + } + return + } + case 'Parameters': { + createPart('Parameters', node.name, node, parentNode, chainParent, 'Parameters') + if (node.baseAsset !== undefined) { + createPartFromNode(node.baseAsset, node, node) + } + return + } case 'Trading System': { let tradingSystem = node createPart('Trading System', tradingSystem.name, tradingSystem, parentNode, chainParent, 'Trading System') @@ -203,6 +230,9 @@ function newPartsFromNodes () { let strategy = node.strategies[m] createPartFromNode(strategy, tradingSystem, tradingSystem) } + if (node.parameters !== undefined) { + createPartFromNode(node.parameters, node, node) + } return } } @@ -222,6 +252,11 @@ function newPartsFromNodes () { }, takePosition: { situations: [] + }, + positionSize: { + formula: { + code: DEFAULT_FORMULA_TEXT + } } }, openStage: { @@ -262,6 +297,31 @@ function newPartsFromNodes () { 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) + } + + function addParameters (node) { + if (node.parameters === undefined) { + node.parameters = { + name: 'Parameters' + } + createPart('Parameters', '', node.parameters, node, node) + addMissingParameters(node.parameters) + } + } + + function addMissingParameters (node) { + if (node.baseAsset === undefined) { + node.baseAsset = { + name: 'Base Asset', + formula: { + code: DEFAULT_FORMULA_TEXT + } + } + createPart('Base Asset', '', node.baseAsset, node, node) + createPart('Formula', '', node.baseAsset.formula, node.baseAsset, node.baseAsset) + } } function addMissingStages (node) { @@ -275,12 +335,19 @@ function newPartsFromNodes () { }, takePosition: { situations: [] + }, + positionSize: { + formula: { + code: DEFAULT_FORMULA_TEXT + } } } createPart('Trigger Stage', '', node.triggerStage, node, node, 'Trigger Stage') 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) { node.openStage = { @@ -339,6 +406,19 @@ 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) { @@ -479,6 +559,9 @@ function newPartsFromNodes () { y: node.savedPayload.targetPosition.y } node.savedPayload.targetPosition = undefined + + if (payload.targetPosition.x === null) { payload.targetPosition.x = spawnPosition.x } + if (payload.targetPosition.y === null) { payload.targetPosition.y = spawnPosition.y } } else { if (chainParent === undefined) { payload.targetPosition = { diff --git a/StrategySpace/Workspace/FunctionLibraries/ProtocolNode.js b/StrategySpace/Workspace/FunctionLibraries/ProtocolNode.js index 5ff9f18cd..481e51241 100644 --- a/StrategySpace/Workspace/FunctionLibraries/ProtocolNode.js +++ b/StrategySpace/Workspace/FunctionLibraries/ProtocolNode.js @@ -155,6 +155,15 @@ function newProtocolNode () { } return object } + case 'Position Size': { + 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, @@ -162,7 +171,8 @@ function newProtocolNode () { name: node.name, triggerOn: getProtocolNode(node.triggerOn), triggerOff: getProtocolNode(node.triggerOff), - takePosition: getProtocolNode(node.takePosition) + takePosition: getProtocolNode(node.takePosition), + positionSize: getProtocolNode(node.positionSize) } return stage } @@ -205,12 +215,31 @@ function newProtocolNode () { } return strategy } + case 'Base Asset': { + let object = { + type: node.type, + subType: node.subType, + name: node.name, + formula: getProtocolNode(node.formula) + } + return object + } + case 'Parameters': { + let object = { + type: node.type, + subType: node.subType, + name: node.name, + baseAsset: getProtocolNode(node.baseAsset) + } + return object + } case 'Trading System': { let tradingSystem = { type: node.type, subType: node.subType, name: node.name, - strategies: [] + strategies: [], + parameters: getProtocolNode(node.parameters) } for (let m = 0; m < node.strategies.length; m++) { diff --git a/StrategySpace/Workspace/FunctionLibraries/WorkspaceNode.js b/StrategySpace/Workspace/FunctionLibraries/WorkspaceNode.js index b11aba2e4..04e69a3fd 100644 --- a/StrategySpace/Workspace/FunctionLibraries/WorkspaceNode.js +++ b/StrategySpace/Workspace/FunctionLibraries/WorkspaceNode.js @@ -181,6 +181,17 @@ function newWorkspaceNode () { } return object } + case 'Position Size': { + let object = { + id: node.id, + type: node.type, + subType: node.subType, + name: node.name, + formula: getWorkspaceNode(node.formula), + savedPayload: getSavedPayload(node) + } + return object + } case 'Trigger Stage': { let stage = { id: node.id, @@ -190,6 +201,7 @@ function newWorkspaceNode () { triggerOn: getWorkspaceNode(node.triggerOn), triggerOff: getWorkspaceNode(node.triggerOff), takePosition: getWorkspaceNode(node.takePosition), + positionSize: getWorkspaceNode(node.positionSize), savedPayload: getSavedPayload(node) } return stage @@ -241,6 +253,28 @@ function newWorkspaceNode () { } return strategy } + case 'Base Asset': { + let object = { + id: node.id, + type: node.type, + subType: node.subType, + name: node.name, + formula: getWorkspaceNode(node.formula), + savedPayload: getSavedPayload(node) + } + return object + } + case 'Parameters': { + let object = { + id: node.id, + type: node.type, + subType: node.subType, + name: node.name, + baseAsset: getWorkspaceNode(node.baseAsset), + savedPayload: getSavedPayload(node) + } + return object + } case 'Trading System': { let tradingSystem = { id: node.id, @@ -248,6 +282,7 @@ function newWorkspaceNode () { subType: node.subType, name: node.name, strategies: [], + parameters: getWorkspaceNode(node.parameters), savedPayload: getSavedPayload(node) } diff --git a/StrategySpace/Workspace/Workspace.js b/StrategySpace/Workspace/Workspace.js index 54b9bf21a..3107151f9 100644 --- a/StrategySpace/Workspace/Workspace.js +++ b/StrategySpace/Workspace/Workspace.js @@ -7,6 +7,7 @@ function newWorkspace () { container: undefined, idAtStrategizer: undefined, onMenuItemClick: onMenuItemClick, + getProtocolTradingSystem: getProtocolTradingSystem, physics: physics, spawn: spawn, detachNode: detachNode, @@ -41,6 +42,7 @@ function newWorkspace () { functionLibraryProtocolNode = newProtocolNode() functionLibraryWorkspaceNodes = newWorkspaceNode() + let isInitialized = false return thisObject function finalize () { @@ -63,36 +65,43 @@ function newWorkspace () { workspace = JSON.parse(savedWorkspace) rootNodes = workspace.rootNodes thisObject.idAtStrategizer = workspace.idAtStrategizer - if (thisObject.idAtStrategizer === undefined) { - initializeLoadingFromStrategizer() - } else { - for (let i = 0; i < rootNodes.length; i++) { - let rootNode = rootNodes[i] - functionLibraryPartsFromNodes.createPartFromNode(rootNode, undefined, undefined) - } + + for (let i = 0; i < rootNodes.length; i++) { + let rootNode = rootNodes[i] + functionLibraryPartsFromNodes.createPartFromNode(rootNode, undefined, undefined) } + isInitialized = true } } async function initializeLoadingFromStrategizer () { - await canvas.strategySpace.strategizerGateway.loadFromStrategyzer() - let tradingSystem = canvas.strategySpace.strategizerGateway.strategizerData - if (tradingSystem !== undefined) { - let adaptedTradingSystem = { - strategies: tradingSystem.subStrategies + let result = await canvas.strategySpace.strategizerGateway.loadFromStrategyzer() + if (result === true) { + thisObject.tradingSystem = canvas.strategySpace.strategizerGateway.strategizerData + rootNodes.push(thisObject.tradingSystem) + functionLibraryPartsFromNodes.createPartFromNode(thisObject.tradingSystem, undefined, undefined) + thisObject.tradingSystem.payload.uiObject.setRunningStatus() + } else { + // First use of the Designer, lets help by creating the first Trading System + thisObject.tradingSystem = { + type: 'Trading System', + strategies: [] } - thisObject.idAtStrategizer = tradingSystem.id - rootNodes.push(adaptedTradingSystem) - functionLibraryPartsFromNodes.createPartFromNode(adaptedTradingSystem, undefined, undefined) - thisObject.tradingSystem = adaptedTradingSystem + rootNodes.push(thisObject.tradingSystem) + functionLibraryPartsFromNodes.createPartFromNode(thisObject.tradingSystem, undefined, undefined) thisObject.tradingSystem.payload.uiObject.setRunningStatus() } + isInitialized = true } function getContainer (point) { } + function getProtocolTradingSystem () { + return functionLibraryProtocolNode.getProtocolNode(thisObject.tradingSystem) + } + function detachNode (node) { functionLibraryAttachDetach.detachNode(node, rootNodes) } @@ -102,6 +111,7 @@ function newWorkspace () { } function physics () { + if (isInitialized !== true) { return } /* Here we will save all the workspace related objects into the local storage */ let stringifyReadyNodes = [] for (let i = 0; i < rootNodes.length; i++) { @@ -159,6 +169,16 @@ function newWorkspace () { functionLibraryPartsFromNodes.newStrategy(payload.node) } break + case 'Add Parameters': + { + functionLibraryPartsFromNodes.addParameters(payload.node) + } + break + case 'Add Missing Parameters': + { + functionLibraryPartsFromNodes.addMissingParameters(payload.node) + } + break case 'Add Missing Stages': { functionLibraryPartsFromNodes.addMissingStages(payload.node) @@ -169,6 +189,11 @@ function newWorkspace () { functionLibraryPartsFromNodes.addMissingEvents(payload.node) } break + case 'Add Position Size': + { + functionLibraryPartsFromNodes.addPositionSize(payload.node) + } + break case 'Add Missing Items': { functionLibraryPartsFromNodes.addMissingItems(payload.node) @@ -213,6 +238,14 @@ function newWorkspace () { functionLibraryNodeDeleter.deleteTradingSystem(payload.node, rootNodes) break } + case 'Delete Parameters': { + functionLibraryNodeDeleter.deleteParameters(payload.node, rootNodes) + break + } + case 'Delete Base Asset': { + functionLibraryNodeDeleter.deleteBaseAsset(payload.node, rootNodes) + break + } case 'Delete Strategy': { functionLibraryNodeDeleter.deleteStrategy(payload.node, rootNodes) break @@ -233,6 +266,10 @@ function newWorkspace () { functionLibraryNodeDeleter.deleteCloseStage(payload.node, rootNodes) break } + case 'Delete Position Size': { + functionLibraryNodeDeleter.deletePositionSize(payload.node, rootNodes) + break + } case 'Delete Initial Definition': { functionLibraryNodeDeleter.deleteInitialDefinition(payload.node, rootNodes) break