Beta 6 without Execution

This commit is contained in:
Luis Fernando Molina committed 2020-07-06 15:43:34 +02:00
1 parent 4033d4d07f
commit d40b985f5e
123 files changed
+8114 -12392

No files matched your search

+19 -8
View File
@@ -54,7 +54,13 @@ function newAppLoader() {
'DesignSpace/Workspace/FunctionLibraries/WebhookFunctions.js',
'DesignSpace/Workspace/FunctionLibraries/DependenciesFilter.js',
'Utilities/RoundedCornersBackground.js',
'Utilities/CoordinateTransformations.js',
'Utilities/DateRateTransformations.js',
'Utilities/Download.js',
'Utilities/DrawPrint.js',
'Utilities/LoadSaveFrame.js',
'Utilities/NodeConfig.js',
'Utilities/HiriarchyMap.js',
'Panels/LayersPanel.js',
'Panels/UpDownButton.js',
@@ -110,22 +116,27 @@ function newAppLoader() {
'EventsServerClient.js',
'VideoRecorder.js',
'Plotter.js',
'Plotting/Plotter.js',
'Plotting/NodesHighlights.js',
'Plotting/NodesErrors.js',
'Plotting/NodesValues.js',
'Plotting/NodesStatus.js',
'Plotting/NodesProgress.js',
'Plotting/NodesRunning.js',
'Plotting/NodesAnnouncements.js',
'Plotting/RecordValues.js',
'LegacyPlotter.js',
'PlotterPanel.js',
'VideoRecorder.js',
'ProductStorage.js',
'SplashScreen.js',
'Canvas.js',
'EventHandler.js',
'Frame.js',
'Animation.js',
'Container.js',
'Utilities.js',
'PostLoader.js'
])
@@ -187,7 +198,7 @@ function newAppLoader() {
'Plotters/TradingEngines/Plotters-Trading-Simulation/TradingSimulation.js',
'Plotters/TradingEngines/Plotters-Trading-Simulation/TradingSimulationAssetBalancesPanel.js',
'Plotters/TradingEngines/Plotters-Trading-Simulation/TradingSimulationCurrentPositionPanel.js',
'Plotters/TradingEngines/Plotters-Trading-Simulation/TradingSimulationPartialResultsPanel.js',
'Plotters/TradingEngines/Plotters-Trading-Simulation/TradingSimulationEpisodePanel.js',
'Plotters/TradingEngines/Plotters-Trading-Simulation/Conditions.js',
'Plotters/TradingEngines/Plotters-Trading-Simulation/Strategies.js',
'Plotters/TradingEngines/Plotters-Trading-Simulation/Trades.js',
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+6 -1
View File
@@ -2,5 +2,10 @@
let functionName = pDataMineOrHost + pPlotter + pModule + pPanel;
functionName = functionName.replace(/-/g, "");
functionName = 'new' + functionName
return window[functionName]();
try {
return window[functionName]();
} catch (err) {
console.log('[ERROR] getNewPlotterPanel -> Error trying to Load a Plotter Panel. err = ' + err.stack)
console.log('[ERROR] getNewPlotterPanel -> functionName = ' + functionName)
}
}
+2
View File
@@ -65,6 +65,8 @@ try {
WEB_SERVER.initialize()
WEB_SERVER.run()
console.log("You are running Superalgos Backend Beta 6.")
} catch (err) {
console.log('[ERROR] BackendServers -> Task Manager -> server -> Error = ' + err.stack)
}
+6 -40
View File
@@ -325,6 +325,12 @@ exports.newWebServer = function newWebServer(EVENTS_SERVER) {
}
break
case 'Plotting': // This means the Plotting folder.
{
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/Plotting/' + requestParameters[2], response)
}
break
case 'TopSpace': // This means the TopSpace folder.
{
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/TopSpace/' + requestParameters[2], response)
@@ -584,46 +590,6 @@ exports.newWebServer = function newWebServer(EVENTS_SERVER) {
}
break
case 'GetDefinition':
{
respondWithFile(process.env.INTER_PROCESS_FILES_PATH + '/definition.json', response)
}
break
case 'SaveDefinition':
{
let fs = require('fs')
let body = ''
request.on('data', function (data) {
body += data
// Too much POST data
if (body.length > 1e6) {
request.connection.destroy()
}
})
request.on('end', function () {
try {
let filePath = process.env.INTER_PROCESS_FILES_PATH + '/definition.json'
fs.writeFile(filePath, body, onFileWrite)
} catch (e) {
console.log('[ERROR] Error writing user config.', e)
respondWithContent(undefined, response)
}
function onFileWrite(err) {
if (err) {
respondWithContent(undefined, response)
} else {
let responseContent = 'User config updated.'
respondWithContent(responseContent, response)
}
}
})
}
break
default:
{
homePage()
+192 -59
View File
@@ -99,7 +99,7 @@ function newPlottersManager () {
for (let i = 0; i < layer.definition.referenceParent.referenceParent.datasets.length; i++) {
let dataset = layer.definition.referenceParent.referenceParent.datasets[i]
switch (dataset.code.type) {
switch (dataset.config.type) {
case 'Market Files': {
storage.onMarketFileLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('Market File Loaded', layer.onMarketFileLoaded)
}
@@ -125,29 +125,43 @@ function newPlottersManager () {
}
}
let baseAsset = layer.definition.referenceParent.parentNode.referenceParent.baseAsset.referenceParent.code.codeName
let quotedAsset = layer.definition.referenceParent.parentNode.referenceParent.quotedAsset.referenceParent.code.codeName
let baseAsset = layer.definition.referenceParent.parentNode.referenceParent.baseAsset.referenceParent.config.codeName
let quotedAsset = layer.definition.referenceParent.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
let market = {
baseAsset: baseAsset,
quotedAsset: quotedAsset
}
let product = layer.definition.referenceParent.referenceParent
let productDefinition = layer.definition.referenceParent.referenceParent
let bot = layer.definition.referenceParent.referenceParent.parentNode
let dataMine = layer.definition.referenceParent.referenceParent.parentNode.parentNode
let exchange = layer.definition.referenceParent.parentNode.referenceParent.parentNode.parentNode
let plotterModule = layer.definition.referenceParent.referenceParent.referenceParent
let session
let tradingSystem
let tradingEngine
/*
A layer can be referencing a Data Product in two different branches of the Network hiriatchy.
In one of those braches we can get the Session node, at the other we Cannot.
*/
if (layer.definition.referenceParent.parentNode.parentNode !== undefined) {
if (layer.definition.referenceParent.parentNode.parentNode.type === 'Session Reference') {
if (layer.definition.referenceParent.parentNode.parentNode.referenceParent !== undefined) {
session = layer.definition.referenceParent.parentNode.parentNode.referenceParent
/* From the session we might be able to reach the Trading System or the Trading Engine */
if (session.tradingSystemReference !== undefined) {
tradingSystem = session.tradingSystemReference.referenceParent
}
if (session.tradingEngineReference !== undefined) {
tradingEngine = session.tradingEngineReference.referenceParent
}
}
}
}
let host = layer.networkNode.code.host
let webPort = layer.networkNode.code.webPort
let host = layer.networkNode.config.host
let webPort = layer.networkNode.config.webPort
if (host === undefined) { host = 'localhost' }
if (webPort === undefined) { webPort = window.location.port }
@@ -157,7 +171,7 @@ function newPlottersManager () {
dataMine,
bot,
session,
product,
productDefinition,
exchange,
market,
datetime,
@@ -169,66 +183,154 @@ function newPlottersManager () {
)
function onProductStorageInitialized (err) {
try {
if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
/* Now we have all the initial data loaded and ready to be delivered to the new instance of the plotter. */
let plotter
let plotter
if (plotterModule.code.isLegacy !== true) {
plotter = newPlotter()
} else {
plotter = getNewPlotter(dataMine.code.codeName, plotterModule.parentNode.code.codeName, plotterModule.code.codeName)
if (plotterModule.config.isLegacy !== true) {
plotter = newPlotter()
} else {
plotter = getNewPlotter(dataMine.config.codeName, plotterModule.parentNode.config.codeName, plotterModule.config.codeName)
}
plotter.container.connectToParent(thisObject.container, true, true, false, true, true, true, false, false, true)
plotter.container.frame.position.x = thisObject.container.frame.width / 2 - plotter.container.frame.width / 2
plotter.container.frame.position.y = thisObject.container.frame.height / 2 - plotter.container.frame.height / 2
plotter.fitFunction = thisObject.fitFunction
plotter.initialize(storage, datetime, timeFrame, coordinateSystem, onPlotterInizialized, productDefinition)
function onPlotterInizialized () {
let connector = {
layer: layer,
plotter: plotter,
storage: storage
}
/* Let the Plotter listen to the event of Cursor Files loaded, so that it can react recalculating if needed. */
plotter.onDailyFileLoadedPlotterEventsSubscriptionId = storage.eventHandler.listenToEvent('Daily File Loaded', plotter.onDailyFileLoaded)
/* Lets load now this plotter panels. */
connector.panels = []
plotter.container.connectToParent(thisObject.container, true, true, false, true, true, true, false, false, true)
plotter.container.frame.position.x = thisObject.container.frame.width / 2 - plotter.container.frame.width / 2
plotter.container.frame.position.y = thisObject.container.frame.height / 2 - plotter.container.frame.height / 2
plotter.fitFunction = thisObject.fitFunction
plotter.initialize(storage, datetime, timeFrame, coordinateSystem, onPlotterInizialized, product)
if (productDefinition !== undefined) {
/* Here we setup the panels associated with this plotter */
for (let i = 0; i < plotterModule.panels.length; i++) {
let panel = plotterModule.panels[i]
function onPlotterInizialized () {
try {
let connector = {
layer: layer,
plotter: plotter,
storage: storage
}
/* Let the Plotter listen to the event of Cursor Files loaded, so that it can react recalculating if needed. */
plotter.onDailyFileLoadedPlotterEventsSubscriptionId = storage.eventHandler.listenToEvent('Daily File Loaded', plotter.onDailyFileLoaded)
/* Lets load now this plotter panels. */
connector.panels = []
if (product !== undefined) {
for (let i = 0; i < plotterModule.panels.length; i++) {
let panel = plotterModule.panels[i]
let parameters = {
dataMine: dataMine.code.codeName,
plotterCodeName: plotterModule.parentNode.code.codeName,
moduleCodeName: plotterModule.code.codeName,
panelNode: panel
}
let owner = thisObject.payload.node.payload.parentNode.id // Panels are owned by the time machine.
let plotterPanelHandle = canvas.panelsSpace.createNewPanel('Plotter Panel', parameters, owner, layer.session)
let plotterPanel = canvas.panelsSpace.getPanel(plotterPanelHandle)
/* Connect Panel to the Plotter via an Event. */
connector.plotter.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', plotterPanel.onRecordChange)
connector.panels.push(plotterPanelHandle)
}
connector.layer.panels = connector.panels
let parameters = {
dataMine: dataMine.config.codeName,
plotterCodeName: plotterModule.parentNode.config.codeName,
moduleCodeName: plotterModule.config.codeName,
panelNode: panel
}
thisObject.connectors.push(connector)
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initializePlotter -> onProductStorageInitialized -> onPlotterInizialized -> err = ' + err.stack) }
let owner = thisObject.payload.node.payload.parentNode.id // Panels are owned by the time machine.
let plotterPanelHandle = canvas.panelsSpace.createNewPanel('Plotter Panel', parameters, owner, layer.session)
let plotterPanel = canvas.panelsSpace.getPanel(plotterPanelHandle)
/* Connect Panel to the Plotter via an Event. */
connector.plotter.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', plotterPanel.onRecordChange)
connector.panels.push(plotterPanelHandle)
}
connector.layer.panels = connector.panels
/*
Next we will check the different types of Plotting related to connecting to an existing node branch.
*/
if (plotterModule.nodesHighlights !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesHighlights = newNodesHighlights()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesHighlights.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesHighlights.initialize(tradingEngine)
break
}
connector.nodesHighlights.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesHighlights.onRecordChange)
}
if (plotterModule.nodesValues !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesValues = newNodesValues()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesValues.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesValues.initialize(tradingEngine)
break
}
connector.nodesValues.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesValues.onRecordChange)
}
if (plotterModule.nodesErrors !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesErrors = newNodesErrors()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesErrors.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesErrors.initialize(tradingEngine)
break
}
connector.nodesErrors.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesErrors.onRecordChange)
}
if (plotterModule.nodesRunning !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesRunning = newNodesRunning()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesRunning.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesRunning.initialize(tradingEngine)
break
}
connector.nodesRunning.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesRunning.onRecordChange)
}
if (plotterModule.nodesStatus !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesStatus = newNodesStatus()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesStatus.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesStatus.initialize(tradingEngine)
break
}
connector.nodesStatus.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesStatus.onRecordChange)
}
if (plotterModule.nodesProgress !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesProgress = newNodesProgress()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesProgress.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesProgress.initialize(tradingEngine)
break
}
connector.nodesProgress.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesProgress.onRecordChange)
}
if (plotterModule.nodesAnnouncements !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesAnnounements = newNodesAnnouncements()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesAnnounements.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesAnnounements.initialize(tradingEngine)
break
}
connector.nodesAnnounements.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesAnnounements.onRecordChange)
}
/*
Another type of plotting is with Record Values. This method uses the record definition to find the target node
and from there is looks into its children all based on the Record Definition configuration.
*/
if (plotterModule.recordValues !== undefined) {
connector.recordValues = newRecordValues()
connector.recordValues.initialize(tradingSystem, tradingEngine, productDefinition)
connector.recordValues.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.recordValues.onRecordChange)
}
}
thisObject.connectors.push(connector)
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initializePlotter -> onProductStorageInitialized -> err = ' + err.stack) }
}
}
} catch (err) {
@@ -262,8 +364,8 @@ function newPlottersManager () {
for (let j = 0; j < connector.panels.length; j++) {
canvas.panelsSpace.destroyPanel(connector.panels[j])
}
/* Finally the Storage Objects */
/* Finally the Storage Objects */
finalizeNodesPlotting(connector)
if (connector.plotter.finalize !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.plotter.onRecordChangeEventsSubscriptionId)
connector.plotter.container.finalize()
@@ -277,6 +379,37 @@ function newPlottersManager () {
}
}
function finalizeNodesPlotting (connector) {
if (connector.nodesHighlights !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesHighlights.onRecordChangeEventsSubscriptionId)
connector.nodesHighlights.finalize()
}
if (connector.nodesValues !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesValues.onRecordChangeEventsSubscriptionId)
connector.nodesValues.finalize()
}
if (connector.nodesErrors !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesErrors.onRecordChangeEventsSubscriptionId)
connector.nodesErrors.finalize()
}
if (connector.nodesStatus !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesStatus.onRecordChangeEventsSubscriptionId)
connector.nodesStatus.finalize()
}
if (connector.nodesProgress !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.Progress.onRecordChangeEventsSubscriptionId)
connector.Progress.finalize()
}
if (connector.nodesRunning !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesRunning.onRecordChangeEventsSubscriptionId)
connector.nodesRunning.finalize()
}
if (connector.recordValues !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.recordValues.onRecordChangeEventsSubscriptionId)
connector.recordValues.finalize()
}
}
function setTimeFrame (pTimeFrame) {
timeFrame = pTimeFrame
for (let i = 0; i < thisObject.connectors.length; i++) {
+11 -11
View File
@@ -369,10 +369,10 @@ function newViewport () {
/* Save the zoom at the node config, so that the user can change it if he wishes to. */
try {
let code = JSON.parse(thisObject.payload.node.code)
code.zoom = (thisObject.zoomTargetLevel - MIN_ZOOM_LEVEL) / (MAX_ZOOM_LEVEL - MIN_ZOOM_LEVEL) * 100
code.zoom = code.zoom.toFixed(2)
thisObject.payload.node.code = JSON.stringify(code)
let config = JSON.parse(thisObject.payload.node.config)
config.zoom = (thisObject.zoomTargetLevel - MIN_ZOOM_LEVEL) / (MAX_ZOOM_LEVEL - MIN_ZOOM_LEVEL) * 100
config.zoom = config.zoom.toFixed(2)
thisObject.payload.node.config = JSON.stringify(config)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
@@ -383,18 +383,18 @@ function newViewport () {
/* Read the zoom level from the node config */
try {
let code = JSON.parse(thisObject.payload.node.code)
let config = JSON.parse(thisObject.payload.node.config)
if (isNaN(code.zoom) || code.zoom === null || code.zoom === undefined) {
if (isNaN(config.zoom) || config.zoom === null || config.zoom === undefined) {
saveObjectState()
return
}
code.zoom = code.zoom / 100 * (MAX_ZOOM_LEVEL - MIN_ZOOM_LEVEL) + MIN_ZOOM_LEVEL
if (code.zoom < MIN_ZOOM_LEVEL) { code.zoom = MIN_ZOOM_LEVEL }
if (code.zoom > MAX_ZOOM_LEVEL) { code.zoom = MAX_ZOOM_LEVEL }
config.zoom = config.zoom / 100 * (MAX_ZOOM_LEVEL - MIN_ZOOM_LEVEL) + MIN_ZOOM_LEVEL
if (config.zoom < MIN_ZOOM_LEVEL) { config.zoom = MIN_ZOOM_LEVEL }
if (config.zoom > MAX_ZOOM_LEVEL) { config.zoom = MAX_ZOOM_LEVEL }
if (code.zoom.toFixed(2) !== thisObject.zoomTargetLevel.toFixed(2)) {
newZoomLevel(code.zoom)
if (config.zoom.toFixed(2) !== thisObject.zoomTargetLevel.toFixed(2)) {
newZoomLevel(config.zoom)
} else {
saveObjectState()
}
@@ -44,7 +44,7 @@ function newCCXTFunctions () {
if (existingExchange === undefined) {
let newExchange = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Crypto Exchange')
newExchange.name = exchange.name
newExchange.code = '{ \n\"codeName\": \"' + exchange.id + '\"\n}'
newExchange.config = '{ \n\"codeName\": \"' + exchange.id + '\"\n}'
newExchange.payload.floatingObject.collapseToggle()
newExchange.exchangeAssets.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
newExchange.exchangeMarkets.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
@@ -114,7 +114,7 @@ function newCCXTFunctions () {
function addAsset (name) {
let newAsseet = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Asset')
newAsseet.name = name
newAsseet.code = '{ \n\"codeName\": \"' + name + '\"\n}'
newAsseet.config = '{ \n\"codeName\": \"' + name + '\"\n}'
}
}
}
@@ -182,7 +182,7 @@ function newCCXTFunctions () {
function addMarket (name, baseAsset, quotedAsset) {
let newMarket = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Market')
newMarket.name = name
newMarket.code = '{ \n\"codeName\": \"' + name + '\"\n}'
newMarket.config = '{ \n\"codeName\": \"' + name + '\"\n}'
newMarket.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
newMarket.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_050X
newMarket.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
@@ -31,11 +31,11 @@ function newChainAttachDetach () {
return
}
default: {
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition (node)
if (nodeDefinition !== undefined) {
/* Detach from parent */
if (node.payload.parentNode !== undefined) {
let parentNodeDefinition = APP_SCHEMA_MAP.get(node.payload.parentNode.type)
let parentNodeDefinition = getNodeDefinition (node.payload.parentNode)
if (parentNodeDefinition !== undefined) {
if (parentNodeDefinition.properties !== undefined) {
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
@@ -166,13 +166,13 @@ function newChainAttachDetach () {
}
break
default: {
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition (node)
if (nodeDefinition !== undefined) {
node.payload.parentNode = attachToNode
node.payload.chainParent = attachToNode
/* Attach to new parent */
if (node.payload.parentNode !== undefined) {
let parentNodeDefinition = APP_SCHEMA_MAP.get(node.payload.parentNode.type)
let parentNodeDefinition = getNodeDefinition (node.payload.parentNode)
if (parentNodeDefinition !== undefined) {
if (parentNodeDefinition.properties !== undefined) {
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
@@ -14,7 +14,7 @@ function newDependenciesFilter () {
function recursiveFilter (node) {
filter(node.code)
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition (node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
@@ -14,7 +14,7 @@ function newNodeChildren () {
childrenCount: 0,
childIndex: undefined
}
let parentNodeDefinition = APP_SCHEMA_MAP.get(parentNode.type)
let parentNodeDefinition = getNodeDefinition (parentNode)
if (parentNodeDefinition !== undefined) {
if (parentNodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
@@ -34,7 +34,7 @@ function newNodeChildren () {
}
break
case 'array': {
let nodeDefinition = APP_SCHEMA_MAP.get(childNode.type)
let nodeDefinition = getNodeDefinition (childNode)
if (nodeDefinition !== undefined) {
let nodePropertyArray = parentNode[property.name]
for (let j = 0; j < nodePropertyArray.length; j++) {
@@ -19,12 +19,13 @@ function newNodeCloning () {
function cloneNode (node) {
if (node === undefined) { return }
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
let object = {
type: node.type,
name: node.name,
code: node.code
code: node.code,
config: node.config
}
/* Children Nodes */
@@ -71,12 +72,13 @@ function newNodeCloning () {
function redirectReferenceParents (node) {
if (node === undefined) { return }
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
let object = {
type: node.type,
name: node.name,
code: node.code
code: node.code,
config: node.config
}
/* Children Nodes */
@@ -29,7 +29,7 @@ function newNodeDeleter () {
node.payload.referenceParent.payload.uiObject.isShowing = false
}
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition (node)
if (nodeDefinition !== undefined) {
/* Remove all of its own children nodes. */
if (nodeDefinition.properties !== undefined) {
@@ -63,7 +63,7 @@ function newNodeDeleter () {
/* Remove node from parent */
if (node.payload !== undefined) {
if (node.payload.parentNode !== undefined) {
let parentNodeDefinition = APP_SCHEMA_MAP.get(node.payload.parentNode.type)
let parentNodeDefinition = getNodeDefinition (node.payload.parentNode)
if (parentNodeDefinition !== undefined) {
if (parentNodeDefinition.properties !== undefined) {
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
@@ -7,7 +7,7 @@ function newOnFocus () {
function getNodeThatIsOnFocus (node) {
if (node === undefined) { return }
if (node.payload === undefined) { return }
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition (node)
if (nodeDefinition !== undefined) {
/* First we ask the question to ourself */
if (node.payload.uiObject.isOnFocus === true) {
@@ -9,17 +9,18 @@ function newProtocolNode () {
}
return thisObject
function getProtocolNode (node, removePersonalData, parseCode, includeIds, includePayload, includeReferencesInSavedPayload, lightingPath) {
function getProtocolNode (node, removePersonalData, parseConfig, includeIds, includePayload, includeReferencesInSavedPayload, lightingPath) {
if (node === undefined) { return }
if (node.payload === undefined) { return }
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
if (removePersonalData === true && nodeDefinition.isPersonalData === true) { return }
let object = {
type: node.type,
name: node.name,
code: node.code
code: node.code,
config: node.config
}
/* Children Nodes */
@@ -31,11 +32,11 @@ function newProtocolNode () {
case 'node': {
if (node[property.name] !== undefined) {
if (lightingPath === undefined) {
object[property.name] = getProtocolNode(node[property.name], removePersonalData, parseCode, includeIds, includeReferencesInSavedPayload, includePayload)
object[property.name] = getProtocolNode(node[property.name], removePersonalData, parseConfig, includeIds, includeReferencesInSavedPayload, includePayload)
} else {
let newLightingPath = getNewLightingPath(lightingPath, node.type, property.childType)
if (newLightingPath !== undefined) {
object[property.name] = getProtocolNode(node[property.name], removePersonalData, parseCode, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
object[property.name] = getProtocolNode(node[property.name], removePersonalData, parseConfig, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
}
}
}
@@ -47,7 +48,7 @@ function newProtocolNode () {
let nodePropertyArray = node[property.name]
object[property.name] = []
for (let m = 0; m < nodePropertyArray.length; m++) {
let protocolNode = getProtocolNode(nodePropertyArray[m], removePersonalData, parseCode, includeIds, includeReferencesInSavedPayload, includePayload)
let protocolNode = getProtocolNode(nodePropertyArray[m], removePersonalData, parseConfig, includeIds, includeReferencesInSavedPayload, includePayload)
if (protocolNode !== undefined) {
object[property.name].push(protocolNode)
}
@@ -58,7 +59,7 @@ function newProtocolNode () {
let nodePropertyArray = node[property.name]
object[property.name] = []
for (let m = 0; m < nodePropertyArray.length; m++) {
let protocolNode = getProtocolNode(nodePropertyArray[m], removePersonalData, parseCode, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
let protocolNode = getProtocolNode(nodePropertyArray[m], removePersonalData, parseConfig, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
if (protocolNode !== undefined) {
object[property.name].push(protocolNode)
}
@@ -76,25 +77,25 @@ function newProtocolNode () {
if (node.payload.parentNode !== undefined) {
let newLightingPath = getNewLightingPath(lightingPath, node.type, node.payload.parentNode.type)
if (newLightingPath !== undefined) {
object.parentNode = getProtocolNode(node.payload.parentNode, removePersonalData, parseCode, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
object.parentNode = getProtocolNode(node.payload.parentNode, removePersonalData, parseConfig, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
}
}
if (node.payload.referenceParent !== undefined) {
let newLightingPath = getNewLightingPath(lightingPath, node.type, node.payload.referenceParent.type)
if (newLightingPath !== undefined) {
object.referenceParent = getProtocolNode(node.payload.referenceParent, removePersonalData, parseCode, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
object.referenceParent = getProtocolNode(node.payload.referenceParent, removePersonalData, parseConfig, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
}
}
if (parseCode && object.code !== undefined && nodeDefinition.editors !== undefined) {
if (parseConfig && object.config !== undefined && nodeDefinition.editors !== undefined) {
if (nodeDefinition.editors.config === true) {
try {
object.code = JSON.parse(node.code)
object.config = JSON.parse(node.config)
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] getProtocolNode -> default -> err = ' + err.stack) }
if (ERROR_LOG === true) { logger.write('[ERROR] getProtocolNode -> default -> node.type = ' + node.type) }
if (ERROR_LOG === true) { logger.write('[ERROR] getProtocolNode -> default -> node.name = ' + node.name) }
if (ERROR_LOG === true) { logger.write('[ERROR] getProtocolNode -> default -> node.code = ' + node.code) }
if (ERROR_LOG === true) { logger.write('[ERROR] getProtocolNode -> default -> node.config = ' + node.config) }
if (ERROR_LOG === true) { logger.write('[ERROR] getProtocolNode -> default -> node.id = ' + node.id) }
}
}
@@ -6,7 +6,7 @@ function newSessionFunctions () {
return thisObject
function runSession (node, functionLibraryProtocolNode, functionLibraryDependenciesFilter, callBackFunction) {
function runSession (node, functionLibraryProtocolNode, functionLibraryDependenciesFilter, resume, callBackFunction) {
if (validations(node) !== true) {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
@@ -24,37 +24,66 @@ function newSessionFunctions () {
'Parameters->' +
'Base Asset->Quoted Asset->Time Range->Time Frame->Slippage->Fee Structure->' +
'Exchange Account Asset->Asset->' +
'Strategy->' +
'Trading Strategy->' +
'Trigger Stage->Trigger On Event->Trigger Off Event->Take Position Event->' +
'Announcement->Formula->' +
'Open Stage->Initial Definition->Open Execution->' +
'Position Size->Position Rate->Formula->' +
'Initial Stop->Initial Take Profit->' +
'Manage Stage->' +
'Stop->Take Profit->' +
'Phase->Formula->Next Phase Event->Move to Phase Event->Phase->' +
'Managed Stop Loss->Managed Take Profit->' +
'Phase->Formula->Next Phase Event->Move To Phase Event->Phase->' +
'Situation->Condition->Javascript Code->' +
'Close Stage->Close Execution->' +
'Announcement->Formula->'
let tradingSystem = functionLibraryProtocolNode.getProtocolNode(node.payload.referenceParent, false, true, true, false, false, lightingPath)
let tradingSystem = functionLibraryProtocolNode.getProtocolNode(node.tradingSystemReference.payload.referenceParent, false, true, true, false, false, lightingPath)
lightingPath = '' +
'Trading Engine->' +
'Dynamic Indicators->Indicator Function->Formula->' +
'Episode->Current->Last->Previous->' +
'Episode Counters->Episode Statistics->' +
'Periods->Positions->Hits->Fails->' +
'Profit Loss->Hit Ratio->Days->ROI->Anualized Rate Of Return->User Defined Statistic->' +
'Formula->' +
'Candle->' +
'Begin->End->Open->Close->Min->Max->Index->' +
'Balance->Base Asset->Quoted Asset->' +
'Distance To Event->' +
'Trigger On->Trigger Off->Take Position->Close Position->Next Phase->Move To Phase->' +
'Strategy->' +
'Begin->End->Strategy Name->Index->Stage Type->Status->Begin Rate->End Rate->Situation Name->' +
'Strategy Counters->Periods->' +
'Position->' +
'Begin->End->Rate->Size->Exit Type->Status->Begin Rate->End Rate->Situation Name->' +
'Stop Loss->Stop Loss Stage->Stop Loss Phase->' +
'Take Profit->Take Profit Stage->Take Profit Phase->' +
'Position Counters->Periods->' +
'Position Statistics->Profit Loss->Days->ROI->Hit Fail->User Defined Statistic->' +
'Formula'
let tradingEngine = functionLibraryProtocolNode.getProtocolNode(node.tradingEngineReference.payload.referenceParent, false, true, true, false, false, lightingPath)
lightingPath = '' +
'Backtesting Session->Paper Trading Session->Fordward Testing Session->Live Trading Session->' +
'Parameters->' +
'Base Asset->Quoted Asset->Time Range->Time Frame->Slippage->Fee Structure->' +
'Session Base Asset->Session Quoted Asset->Time Range->Time Frame->Slippage->Fee Structure->Snapshots->User Defined Parameters->' +
'Exchange Account Asset->Asset->' +
'Social Bots->Telegram Bot->'
let session = functionLibraryProtocolNode.getProtocolNode(node, false, true, true, false, false, lightingPath)
let dependencyFilter = functionLibraryDependenciesFilter.createFilter(node.payload.referenceParent)
let dependencyFilter = functionLibraryDependenciesFilter.createFilter(node.tradingSystemReference.payload.referenceParent)
/* Raise event to run the session */
let event = {
appSchema: JSON.stringify(APP_SCHEMA_ARRAY),
session: JSON.stringify(session),
tradingSystem: JSON.stringify(tradingSystem),
dependencyFilter: JSON.stringify(dependencyFilter)
tradingEngine: JSON.stringify(tradingEngine),
dependencyFilter: JSON.stringify(dependencyFilter),
resume: resume
}
eventsServerClient.raiseEvent(key, 'Run Session', event)
@@ -121,8 +150,23 @@ function newSessionFunctions () {
return
}
if (node.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('Session needs to reference a Trading System.')
if (node.tradingSystemReference === undefined) {
node.payload.uiObject.setErrorMessage('Session needs a child Trading System Reference.')
return
}
if (node.tradingEngineReference === undefined) {
node.payload.uiObject.setErrorMessage('Session needs a child Trading Engine Reference.')
return
}
if (node.tradingSystemReference.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('Trading System Reference needs to reference a Trading System.')
return
}
if (node.tradingEngineReference.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('Trading Engine Reference needs to reference a Trading Engine.')
return
}
return true
@@ -6,7 +6,7 @@ function newShortcutKeys () {
function getNodeByShortcutKey (node, searchingKey) {
if (node === undefined) { return }
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition (node)
if (nodeDefinition !== undefined) {
/* Check Self first */
if (node.payload.uiObject.shortcutKey === searchingKey) {
@@ -18,7 +18,7 @@ function newSuperScriptsFunctions () {
if (exchange === undefined) {
functionLibraryUiObjectsFromNodes.createUiObjectFromNode(templateClone, target, target)
} else {
let definition = APP_SCHEMA_MAP.get(target.type)
let definition = getNodeDefinition (target)
for (let i = 0; i < definition.properties.length; i++) {
let property = definition.properties[i]
if (property.childType === exchangeNodeType) {
@@ -26,14 +26,14 @@ function newUiObjectsFromNodes () {
function addIncludedNodes () {
let blobService = newFileStorage()
// if (node.code === undefined) {
node.code = '{ \n"includeDataMines": ["Masters", "Sparta", "TradingEngines"],\n"includeTradingSystems": ["Sparta-WHB-BTC-USDT", "Example-ETH-USDT", "Sparta-BRR-BTC-USDT"],\n"includeSuperScripts": ["Masters"]\n }'
// if (node.config === undefined) {
node.config = '{ \n"includeDataMines": ["Masters", "Sparta", "Masters-Trading"],\n"includeTradingSystems": ["Sparta-WHB-BTC-USDT", "Example-ETH-USDT", "Sparta-BRR-BTC-USDT"],\n"includeSuperScripts": ["Masters"]\n }'
// }
let code = JSON.parse(node.code)
let includeDataMines = code.includeDataMines
let includeTradingSystems = code.includeTradingSystems
let includeSuperScripts = code.includeSuperScripts
let config = JSON.parse(node.config)
let includeDataMines = config.includeDataMines
let includeTradingSystems = config.includeTradingSystems
let includeSuperScripts = config.includeSuperScripts
let totalIncluded = 0
@@ -49,9 +49,9 @@ function newUiObjectsFromNodes () {
for (let i = 0; i < node.rootNodes.length; i++) {
let rootNode = node.rootNodes[i]
if (rootNode.type === 'Data Mine') {
if (rootNode.code !== undefined) {
let code = JSON.parse(rootNode.code)
if (code.name === name) {
if (rootNode.config !== undefined) {
let config = JSON.parse(rootNode.config)
if (config.name === name) {
rootNodes.splice(i, 1)
}
}
@@ -78,9 +78,9 @@ function newUiObjectsFromNodes () {
for (let i = 0; i < node.rootNodes.length; i++) {
let rootNode = node.rootNodes[i]
if (rootNode.type === 'Trading System') {
if (rootNode.code !== undefined) {
let code = JSON.parse(rootNode.code)
if (code.name === name) {
if (rootNode.config !== undefined) {
let config = JSON.parse(rootNode.config)
if (config.name === name) {
rootNodes.splice(i, 1)
}
}
@@ -107,9 +107,9 @@ function newUiObjectsFromNodes () {
for (let i = 0; i < node.rootNodes.length; i++) {
let rootNode = node.rootNodes[i]
if (rootNode.type === 'Super Scripts') {
if (rootNode.code !== undefined) {
let code = JSON.parse(rootNode.code)
if (code.name === name) {
if (rootNode.config !== undefined) {
let config = JSON.parse(rootNode.config)
if (config.name === name) {
rootNodes.splice(i, 1)
}
}
@@ -179,10 +179,33 @@ function newUiObjectsFromNodes () {
}
}
function migrateCodeToConfig (node, nodeDefinition) {
/* Code needed to Migrante from Beta 5 to Beta a Workspace */
if (nodeDefinition.editors !== undefined) {
if (nodeDefinition.editors.config === true) {
if (node.code !== undefined) {
node.config = node.code
node.code = undefined
}
}
}
}
function createUiObjectFromNode (node, parentNode, chainParent, positionOffset) {
/* Code needed to Migrante from Beta 5 to Beta 6 a Trading System
if (node.type === 'Take Profit') {
node.type = 'Managed Take Profit'
}
if (node.type === 'Stop') {
node.type = 'Managed Stop Loss'
}
*/
/* Get node definition */
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
migrateCodeToConfig(node, nodeDefinition)
/* Resolve Initial Values */
if (nodeDefinition.initialValues !== undefined) {
if (nodeDefinition.initialValues.code !== undefined) {
@@ -190,12 +213,17 @@ function newUiObjectsFromNodes () {
node.code = nodeDefinition.initialValues.code
}
}
if (nodeDefinition.initialValues.config !== undefined) {
if (node.config === undefined) {
node.config = nodeDefinition.initialValues.config
}
}
}
/* For the cases where an node is not chained to its parent but to the one at the parent before it at its collection */
if (nodeDefinition.chainedToSameType === true) {
if (parentNode !== undefined) {
let parentNodeDefinition = APP_SCHEMA_MAP.get(parentNode.type)
let parentNodeDefinition = getNodeDefinition(parentNode)
if (parentNodeDefinition !== undefined) {
if (parentNodeDefinition.properties !== undefined) {
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
@@ -263,12 +291,12 @@ function newUiObjectsFromNodes () {
type: type
}
let parentNodeDefinition = APP_SCHEMA_MAP.get(parentNode.type)
let parentNodeDefinition = getNodeDefinition(parentNode)
if (parentNodeDefinition === undefined) {
console.log('Cannot addUIOBject from parent of ' + type + ' because that type it is not defined at the APP_SCHEMA.')
}
/* Resolve Initial Values */
let nodeDefinition = APP_SCHEMA_MAP.get(object.type)
let nodeDefinition = getNodeDefinition(object)
if (nodeDefinition === undefined) {
console.log('Cannot addUIOBject of ' + type + ' because that type it is not defined at the APP_SCHEMA.')
@@ -279,6 +307,11 @@ function newUiObjectsFromNodes () {
object.code = nodeDefinition.initialValues.code
}
}
if (nodeDefinition.initialValues !== undefined) {
if (nodeDefinition.initialValues.config !== undefined) {
object.config = nodeDefinition.initialValues.config
}
}
if (nodeDefinition.isHierarchyHead === true) {
parentNode.rootNodes.push(object)
@@ -321,6 +354,9 @@ function newUiObjectsFromNodes () {
if (nodeDefinition.initialValues.code !== undefined) {
object.code = nodeDefinition.initialValues.code
}
if (nodeDefinition.initialValues.config !== undefined) {
object.config = nodeDefinition.initialValues.config
}
}
}
@@ -393,7 +429,7 @@ function newUiObjectsFromNodes () {
}
function addMissingChildren (node) {
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition(node)
/* Connect to Parent */
if (nodeDefinition.properties !== undefined) {
+22 -6
View File
@@ -14,6 +14,7 @@ function newWorkspace () {
replaceWorkspaceByLoadingOne: replaceWorkspaceByLoadingOne,
save: saveWorkspace,
getHierarchyHeads: getHierarchyHeads,
getHierarchyHeadsById: getHierarchyHeadsById,
getNodeThatIsOnFocus: getNodeThatIsOnFocus,
getNodeByShortcutKey: getNodeByShortcutKey,
stopAllRunningTasks: stopAllRunningTasks,
@@ -148,9 +149,9 @@ function newWorkspace () {
let webSocketsPort
/* At this point the node does not have the payload property yet, that is why we have to do this manually */
try {
let code = JSON.parse(networkNode.code)
host = code.host
webSocketsPort = code.webSocketsPort
let config = JSON.parse(networkNode.config)
host = config.host
webSocketsPort = config.webSocketsPort
} catch (err) {
console.log('[ERROR] networkNode ' + networkNode.name + ' has an invalid configuration. Cannot know the host name and webSocketsPort.')
return
@@ -345,7 +346,7 @@ function newWorkspace () {
let nodes = []
for (let i = 0; i < thisObject.workspaceNode.rootNodes.length; i++) {
let rootNode = thisObject.workspaceNode.rootNodes[i]
let nodeDefinition = APP_SCHEMA_MAP.get(rootNode.type)
let nodeDefinition = getNodeDefinition(rootNode)
if (nodeDefinition !== undefined) {
if (nodeDefinition.isHierarchyHead === true) {
nodes.push(rootNode)
@@ -355,6 +356,16 @@ function newWorkspace () {
return nodes
}
function getHierarchyHeadsById (nodeId) {
let hiriatchyHeads = getHierarchyHeads()
for (let i = 0; i < hiriatchyHeads.length; i++) {
let hiriatchyHead = hiriatchyHeads[i]
if (hiriatchyHead.id === nodeId) {
return hiriatchyHead
}
}
}
function replaceWorkspaceByLoadingOne (name) {
let blobService = newFileStorage()
blobService.getFileFromHost('LoadWorkspace' + '/' + name, onFileReceived, true)
@@ -561,7 +572,12 @@ function newWorkspace () {
break
case 'Run Session':
{
functionLibrarySessionFunctions.runSession(payload.node, functionLibraryProtocolNode, functionLibraryDependenciesFilter, callBackFunction)
functionLibrarySessionFunctions.runSession(payload.node, functionLibraryProtocolNode, functionLibraryDependenciesFilter, false, callBackFunction)
}
break
case 'Resume Session':
{
functionLibrarySessionFunctions.runSession(payload.node, functionLibraryProtocolNode, functionLibraryDependenciesFilter, true, callBackFunction)
}
break
case 'Stop Session':
@@ -596,7 +612,7 @@ function newWorkspace () {
break
case 'Open Documentation':
{
let definition = APP_SCHEMA_MAP.get(payload.node.type)
let definition = getNodeDefinition(payload.node)
if (definition !== undefined) {
if (definition.docURL !== undefined) {
let newTab = window.open(definition.docURL, '_blank')
+4 -4
View File
@@ -52,10 +52,10 @@ function newConfigEditor () {
thisObject.visible = false
let textArea = document.getElementById('textArea')
textArea.style.display = 'none'
thisObject.payload.node.code = textArea.value
thisObject.payload.node.config = textArea.value
try {
let code = JSON.parse(thisObject.payload.node.code)
let config = JSON.parse(thisObject.payload.node.config)
} catch (err) {
thisObject.payload.uiObject.setErrorMessage(err.message, 10)
}
@@ -72,7 +72,7 @@ function newConfigEditor () {
thisObject.payload.uiObject.setErrorMessage('', 0)
let textArea = document.getElementById('textArea')
textArea.value = payload.node.code
textArea.value = payload.node.config
textArea.style = 'resize: none;' +
' border: none;' +
' outline: none;' +
@@ -94,7 +94,7 @@ function newConfigEditor () {
if (thisObject.visible === true) {
if (point.x === VERY_LARGE_NUMBER) {
/* The the mouse leaves the canvas, and event of mouse over with a ridiculous coordinate is triggered so that
anyone can react. In our case, the code editor has a text area that is not part of the canvas, so the event is
anyone can react. In our case, the config editor has a text area that is not part of the canvas, so the event is
triggered. We compensate recognizing this coordinate and returning our container. */
return thisObject.container
}
+121 -36
View File
@@ -20,7 +20,6 @@ function newUiObject () {
formulaEditor: undefined,
uiObjectTitle: undefined,
circularProgressBar: undefined,
isExecuting: undefined,
isRunning: undefined,
shortcutKey: undefined,
isShowing: undefined,
@@ -32,10 +31,15 @@ function newUiObject () {
getReadyToReferenceAttach: getReadyToReferenceAttach,
showAvailabilityToReferenceAttach: showAvailabilityToReferenceAttach,
highlight: highlight,
runningAtBackend: runningAtBackend,
setErrorMessage: setErrorMessage,
resetErrorMessage: resetErrorMessage,
setValue: setValue,
resetValue: resetValue,
setPercentage: setPercentage,
resetPercentage: resetPercentage,
setStatus: setStatus,
resetStatus: resetStatus,
physics: physics,
invisiblePhysics: invisiblePhysics,
drawBackground: drawBackground,
@@ -67,6 +71,9 @@ function newUiObject () {
let isHighlighted
let highlightCounter = 0
let isRunningAtBackend
let runningAtBackendCounter = 0
let hasError
let errorMessageCounter = 0
@@ -107,6 +114,7 @@ function newUiObject () {
let currentStatus = ''
let rightDragging = false
let eventSubscriptionIdOnError
let eventSubscriptionIdOnRunning
let eventSubscriptionIdOnStopped
let lastHeartBeat
@@ -178,6 +186,9 @@ function newUiObject () {
if (eventSubscriptionIdOnStopped !== undefined) {
eventsServerClient.stopListening(key, eventSubscriptionIdOnStopped, 'UiObject')
}
if (eventSubscriptionIdOnError !== undefined) {
eventsServerClient.stopListening(key, eventSubscriptionIdOnError, 'UiObject')
}
}
}
@@ -313,6 +324,7 @@ function newUiObject () {
iconPhysics()
highlightPhisycs()
runningAtBackendPhisycs()
errorMessagePhisycs()
valuePhisycs()
percentagePhisycs()
@@ -363,7 +375,7 @@ function newUiObject () {
}
function childrenRunningPhysics () {
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
let nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition.properties === undefined) { return }
let monitorChildrenRunning = false
for (let i = 0; i < nodeDefinition.properties.length; i++) {
@@ -407,7 +419,7 @@ function newUiObject () {
let nearbyFloatingObjects = thisObject.payload.floatingObject.nearbyFloatingObjects
let compatibleTypes
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
let nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.chainAttachesTo !== undefined) {
compatibleTypes = nodeDefinition.chainAttachesTo.compatibleTypes
@@ -429,10 +441,10 @@ function newUiObject () {
let nearbyNode = floatingObject.payload.node
if (compatibleTypes.indexOf('->' + nearbyNode.type + '->') >= 0) {
/* Discard App Schema defined objects with busy coonection ports */
nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition !== undefined) {
let mustContinue = false
let parentNodeDefinition = APP_SCHEMA_MAP.get(nearbyNode.type)
let parentNodeDefinition = getNodeDefinition(nearbyNode)
if (parentNodeDefinition !== undefined) {
if (parentNodeDefinition.properties !== undefined) {
for (let j = 0; j < parentNodeDefinition.properties.length; j++) {
@@ -560,7 +572,7 @@ function newUiObject () {
let nearbyFloatingObjects = thisObject.payload.floatingObject.nearbyFloatingObjects
let compatibleTypes
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
let nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.referenceAttachesTo !== undefined) {
compatibleTypes = nodeDefinition.referenceAttachesTo.compatibleTypes
@@ -664,6 +676,14 @@ function newUiObject () {
}
}
function runningAtBackendPhisycs () {
runningAtBackendCounter--
if (runningAtBackendCounter < 0) {
runningAtBackendCounter = 0
isRunningAtBackend = false
}
}
function errorMessagePhisycs () {
errorMessageCounter--
if (errorMessageCounter < 0) {
@@ -696,9 +716,18 @@ function newUiObject () {
}
}
function highlight () {
function highlight (counter) {
isHighlighted = true
highlightCounter = 30
if (counter !== undefined) {
highlightCounter = counter
} else {
highlightCounter = 30
}
}
function runningAtBackend () {
isRunningAtBackend = true
runningAtBackendCounter = 5
}
function setErrorMessage (message, duration) {
@@ -710,6 +739,11 @@ function newUiObject () {
}
}
function resetErrorMessage () {
errorMessage = undefined
hasError = false
}
function setValue (value, counter) {
if (value !== undefined) {
currentValue = value
@@ -722,6 +756,12 @@ function newUiObject () {
}
}
function resetValue () {
currentValue = undefined
hasValue = false
valueCounter = 0
}
function setPercentage (percentage, counter) {
if (percentage !== undefined) {
currentPercentage = percentage
@@ -734,6 +774,12 @@ function newUiObject () {
}
}
function resetPercentage () {
currentPercentage = undefined
hasPercentage = false
percentageCounter = 0
}
function setStatus (status, counter) {
if (status !== undefined) {
currentStatus = status
@@ -746,6 +792,12 @@ function newUiObject () {
}
}
function resetStatus () {
currentStatus = undefined
hasStatus = false
statusCounter = 0
}
function heartBeat () {
lastHeartBeat = new Date()
thisObject.isRunning = true
@@ -760,6 +812,10 @@ function newUiObject () {
function run (pEventsServerClient, callBackFunction) {
finalizeEventsServerClient()
resetErrorMessage()
resetPercentage()
resetValue()
resetStatus()
eventsServerClient = pEventsServerClient
/* We setup the circular progress bar. */
@@ -772,7 +828,12 @@ function newUiObject () {
thisObject.circularProgressBar.fitFunction = thisObject.fitFunction
thisObject.circularProgressBar.container = thisObject.container
/* We will wait to hear the Running event in order to confirm the execution was really started */
setupRunningEventListener(callBackFunction)
setupErrorEventListener(callBackFunction)
}
function setupRunningEventListener (callBackFunction) {
/* We will wait to hear the Running event in order to confirm the execution was really started */
let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id
eventsServerClient.listenToEvent(key, 'Running', undefined, 'UiObject', onResponse, onRunning)
@@ -813,6 +874,24 @@ function newUiObject () {
stop(callBackFunction, event)
}
function setupErrorEventListener (callBackFunction) {
let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id
eventsServerClient.listenToEvent(key, 'Error', undefined, key, onResponse, onError)
function onResponse (message) {
eventSubscriptionIdOnError = message.eventSubscriptionId
}
function onError (message) {
setErrorMessage(message.event.errorMessage, 10)
let event = {
type: 'Secondary Action Already Executed'
}
completeStop(callBackFunction, event)
}
}
function stop (callBackFunction, event) {
/* We will wait to the event that the execution was terminated in order to call back the menu item */
let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id
@@ -823,26 +902,32 @@ function newUiObject () {
}
function onStopped () {
if (thisObject.payload === undefined) { return }
if (callBackFunction !== undefined) {
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE, event)
}
if (thisObject.circularProgressBar !== undefined) {
thisObject.circularProgressBar.finalize()
thisObject.circularProgressBar = undefined
}
thisObject.isRunning = false
hasValue = false
hasPercentage = false
hasStatus = false
lastHeartBeat = undefined
completeStop(callBackFunction, event)
}
}
function completeStop (callBackFunction, event) {
if (thisObject.payload === undefined) { return }
if (callBackFunction !== undefined) {
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE, event)
}
if (thisObject.circularProgressBar !== undefined) {
thisObject.circularProgressBar.finalize()
thisObject.circularProgressBar = undefined
}
thisObject.isRunning = false
hasValue = false
hasPercentage = false
hasStatus = false
lastHeartBeat = undefined
finalizeEventsServerClient()
}
function iconPhysics () {
icon = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.type)
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
let nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition.alternativeIcons !== undefined) {
let nodeToUse = thisObject.payload.node
if (nodeDefinition.alternativeIcons === 'Use Reference Parent') {
@@ -859,15 +944,15 @@ function newUiObject () {
}
}
}
nodeDefinition = APP_SCHEMA_MAP.get(nodeToUse.type)
let code = nodeToUse.code
nodeDefinition = getNodeDefinition(nodeToUse)
let config = nodeToUse.config
try {
code = JSON.parse(code)
config = JSON.parse(config)
let alternativeIcon
let iconName
for (let i = 0; i < nodeDefinition.alternativeIcons.length; i++) {
alternativeIcon = nodeDefinition.alternativeIcons[i]
if (alternativeIcon.codeName === code.codeName) {
if (alternativeIcon.codeName === config.codeName) {
iconName = alternativeIcon.iconName
}
}
@@ -1261,7 +1346,7 @@ function newUiObject () {
if (canvas.floatingSpace.inMapMode === true) {
labelPoint.y = labelPoint.y - 20
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
let nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.isHierarchyHead !== true) {
return
@@ -1291,7 +1376,7 @@ function newUiObject () {
position = canvas.floatingSpace.transformPointToMap(position)
}
let radius = thisObject.container.frame.radius * 3.5
let radius = thisObject.container.frame.radius * 2.5
/* Label Text */
let labelPoint
let fontSize = thisObject.payload.floatingObject.currentFontSize * 3 / 4
@@ -1351,7 +1436,7 @@ function newUiObject () {
label = currentValue
if (!isNaN(label)) {
if (currentValue.toFixed !== undefined) {
label = dynamicDecimals(currentValue, 2)
label = dynamicDecimals(currentValue)
}
}
@@ -1578,7 +1663,7 @@ function newUiObject () {
browserCanvasContext.fill()
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
let nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.isHierarchyHead === true) {
VISIBLE_RADIUS = thisObject.payload.floatingObject.currentHierarchyRing * 2.8
@@ -1637,7 +1722,7 @@ function newUiObject () {
if (isHighlighted === true) {
VISIBLE_RADIUS = thisObject.container.frame.radius * 1
let OPACITY = highlightCounter / 30
let OPACITY = highlightCounter / 10
browserCanvasContext.beginPath()
browserCanvasContext.arc(visiblePosition.x, visiblePosition.y, VISIBLE_RADIUS, 0, Math.PI * 2, true)
@@ -1756,11 +1841,11 @@ function newUiObject () {
if (icon !== undefined) {
if (icon.canDrawIcon === true) {
let additionalImageSize = 0
if (thisObject.isExecuting === true || isReadyToReferenceAttach === true || isReadyToChainAttach === true) { additionalImageSize = 20 }
if (isRunningAtBackend === true || isReadyToReferenceAttach === true || isReadyToChainAttach === true) { additionalImageSize = 20 }
let totalImageSize = additionalImageSize + thisObject.payload.floatingObject.currentImageSize
if (canvas.floatingSpace.inMapMode === true) {
totalImageSize = canvas.floatingSpace.transformImagesizeToMap(totalImageSize)
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
let nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.isHierarchyHead !== true) {
totalImageSize = totalImageSize / 4
@@ -1782,7 +1867,7 @@ function newUiObject () {
if (executingIcon !== undefined) {
if (executingIcon.canDrawIcon === true) {
if (thisObject.isExecuting === true) {
if (isRunningAtBackend === true) {
const DISTANCE_FROM_CENTER = thisObject.container.frame.radius / 3 + 50
const EXECUTING_ICON_SIZE = 20 + thisObject.container.frame.radius / 6
@@ -74,7 +74,7 @@ function newUiObjectConstructor () {
*/
if (userAddingNew === true) {
let definition = APP_SCHEMA_MAP.get(payload.parentNode.type)
let definition = getNodeDefinition (payload.parentNode)
if (definition.properties !== undefined) {
for (let i = 0; i < definition.properties.length; i++) {
let property = definition.properties[i]
@@ -406,7 +406,7 @@ function newUiObjectConstructor () {
function getMenuItemsInitialValues (uiObject, floatingObject, payload) {
let menuItemsInitialValues = []
let nodeDefinition = APP_SCHEMA_MAP.get(payload.node.type)
let nodeDefinition = getNodeDefinition (payload.node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.editors !== undefined) {
if (nodeDefinition.editors.config === true) {
@@ -495,7 +495,7 @@ function newUiObjectConstructor () {
}
default: {
let nodeDefinition = APP_SCHEMA_MAP.get(payload.node.type)
let nodeDefinition = getNodeDefinition (payload.node)
if (nodeDefinition !== undefined) {
switch (nodeDefinition.level) {
case 0: {
+4 -4
View File
@@ -51,7 +51,7 @@ function newUiObjectTitle () {
thisObject.payload = payload
thisObject.allwaysVisible = false // Default value
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
let nodeDefinition = getNodeDefinition (thisObject.payload.node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.isTitleAllwaysVisible === true) {
thisObject.allwaysVisible = true
@@ -100,7 +100,7 @@ function newUiObjectTitle () {
if (thisObject.payload.title === undefined) { return }
/* It is possible to override the default title by setting the APP SCHEMA property 'title' */
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
let nodeDefinition = getNodeDefinition (thisObject.payload.node)
if (nodeDefinition.title !== undefined) {
thisObject.payload.title = ''
thisObject.payload.node.name = ''
@@ -221,7 +221,7 @@ function newUiObjectTitle () {
}
function onMouseClick (event) {
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
let nodeDefinition = getNodeDefinition (thisObject.payload.node)
if (nodeDefinition.title !== undefined) { return }
let checkPoint = {
@@ -329,7 +329,7 @@ function newUiObjectTitle () {
labelPoint.x = labelPoint.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO
labelPoint.y = labelPoint.y - 35
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
let nodeDefinition = getNodeDefinition (thisObject.payload.node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.isHierarchyHead !== true) {
return
+12 -9
View File
@@ -157,6 +157,7 @@ function newLayer () {
'Session Reference->Session Independent Data->Session Based Data->Exchange Sessions->Session Based Data->Data Storage->Network Node->' +
'Data Storage->Network Node->' +
'Backtesting Session->Paper Trading Session->Fordward Testing Session->Live Trading Session->' +
'Trading System Reference->Trading Engine Reference->Trading System->Trading Engine->' +
'Market->Market Base Asset->Asset->' +
'Market Quoted Asset->Asset->' +
'Exchange Markets->Crypto Exchange->' +
@@ -173,12 +174,15 @@ function newLayer () {
'Polygon->Polygon Condition->Polygon Body->Style->Style Condition->Style->' +
'Polygon Border->Style->Style Condition->Style->' +
'Polygon Vertex->Point->' +
'Plotter Panel->Javascript Code->Panel Data->Data Formula->'
'Image->Image Condition->Image Position->Point->' +
'Text->Text Condition->Text Position->Point->Text Formula->Text Style->' +
'Plotter Panel->Javascript Code->Panel Data->Data Formula->' +
'Nodes Highlights->Nodes Values->Nodes Errors->Nodes Status->Nodes Progress->Nodes Running->Nodes Announcements->Record Values->'
thisObject.definition = functionLibraryProtocolNode.getProtocolNode(thisObject.payload.node, false, true, true, false, false, lightingPath)
/* Here we validate that we have all the needed information */
if (thisObject.definition.referenceParent === undefined) { return }
if (thisObject.definition.referenceParent.parentNode === undefined) { return }
if (thisObject.definition.referenceParent === undefined) { return } // Data Product
if (thisObject.definition.referenceParent.parentNode === undefined) { return } // Single Market Data
if (thisObject.definition.referenceParent.parentNode.referenceParent === undefined) { return }
if (thisObject.definition.referenceParent.parentNode.referenceParent.parentNode === undefined) { return }
if (thisObject.definition.referenceParent.parentNode.referenceParent.parentNode.parentNode === undefined) { return }
@@ -200,7 +204,7 @@ function newLayer () {
/* Get ready to draw this layer */
thisObject.baseAsset = thisObject.definition.referenceParent.parentNode.referenceParent.baseAsset.referenceParent
thisObject.quotedAsset = thisObject.definition.referenceParent.parentNode.referenceParent.quotedAsset.referenceParent
thisObject.market = thisObject.baseAsset.code.codeName + '/' + thisObject.quotedAsset.code.codeName
thisObject.market = thisObject.baseAsset.config.codeName + '/' + thisObject.quotedAsset.config.codeName
thisObject.exchange = thisObject.definition.referenceParent.parentNode.referenceParent.parentNode.parentNode
/* Some basic validations. */
@@ -223,11 +227,10 @@ function newLayer () {
}
thisObject.plotterModule = thisObject.definition.referenceParent.referenceParent.referenceParent
thisObject.exchangeIcon = getIcon(thisObject.exchange)
if (thisObject.plotterModule.code.icon !== undefined) {
thisObject.plotterTypeIcon = canvas.designSpace.iconCollection.get(thisObject.plotterModule.code.icon)
if (thisObject.plotterModule.config.icon !== undefined) {
thisObject.plotterTypeIcon = canvas.designSpace.iconCollection.get(thisObject.plotterModule.config.icon)
}
thisObject.baseAssetIcon = getIcon(thisObject.baseAsset)
@@ -240,12 +243,12 @@ function newLayer () {
}
function getIcon (node) {
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let nodeDefinition = getNodeDefinition(node)
let iconName
if (nodeDefinition.alternativeIcons !== undefined) {
for (let i = 0; i < nodeDefinition.alternativeIcons.length; i++) {
alternativeIcon = nodeDefinition.alternativeIcons[i]
if (alternativeIcon.codeName === node.code.codeName) {
if (alternativeIcon.codeName === node.config.codeName) {
iconName = alternativeIcon.iconName
}
}
+9 -11
View File
@@ -100,9 +100,7 @@ function newPlotterPanel () {
const PANEL_HEIGHT = UI_PANEL.HEIGHT.NORMAL
if (currentRecord === undefined) { return }
if (currentRecord.data === undefined) { return }
let record = currentRecord.data
let record = currentRecord
/* First we execute code if provided. */
if (panelNode.javascriptCode !== undefined) {
@@ -151,24 +149,24 @@ function newPlotterPanel () {
}
}
if (panelData.code.valueDecimals !== undefined) {
if (panelData.config.valueDecimals !== undefined) {
if (value !== undefined) {
if (isNaN(value) === false) {
value = dynamicDecimals(value, panelData.code.valueDecimals)
value = dynamicDecimals(value, panelData.config.valueDecimals)
}
}
}
if (panelData.code.labelText !== undefined) {
labelText = panelData.code.labelText
if (panelData.config.labelText !== undefined) {
labelText = panelData.config.labelText
}
if (panelData.code.labelPosition !== undefined) {
labelPosition = panelData.code.labelPosition
if (panelData.config.labelPosition !== undefined) {
labelPosition = panelData.config.labelPosition
}
if (panelData.code.valuePosition !== undefined) {
valuePosition = panelData.code.valuePosition
if (panelData.config.valuePosition !== undefined) {
valuePosition = panelData.config.valuePosition
}
printLabel(labelText, X_AXIS, UI_PANEL.HEIGHT.NORMAL * labelPosition / 100 / heightFactor, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction)
+46
View File
@@ -0,0 +1,46 @@
function newNodesAnnouncements () {
const MODULE_NAME = 'Nodes Announcements'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize () {
hiriarchyMap = undefined
}
function initialize (pRootNode) {
let rootNode = canvas.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = getHiriarchyMap(rootNode)
}
function onRecordChange (currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.announcements
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue (nodeId, value) {
if (canvas.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.setValue(value, 20)
}
}
+47
View File
@@ -0,0 +1,47 @@
function newNodesErrors () {
const MODULE_NAME = 'Nodes Errors'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize () {
hiriarchyMap = undefined
}
function initialize (pRootNode) {
let rootNode = canvas.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = getHiriarchyMap(rootNode)
}
function onRecordChange (currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.errors
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue (nodeId, value) {
if (canvas.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === '') {
node.payload.uiObject.resetErrorMessage()
} else {
node.payload.uiObject.setErrorMessage(value)
}
}
}
+42
View File
@@ -0,0 +1,42 @@
function newNodesHighlights () {
const MODULE_NAME = 'Nodes Highlights'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize () {
hiriarchyMap = undefined
}
function initialize (pRootNode) {
let rootNode = canvas.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = getHiriarchyMap(rootNode)
}
function onRecordChange (currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.highlights
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let nodeId = array[i]
highlight(nodeId)
}
}
function highlight (nodeId) {
if (canvas.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
node.payload.uiObject.highlight(10)
}
}
+47
View File
@@ -0,0 +1,47 @@
function newNodesProgress () {
const MODULE_NAME = 'Nodes Progress'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize () {
hiriarchyMap = undefined
}
function initialize (pRootNode) {
let rootNode = canvas.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = getHiriarchyMap(rootNode)
}
function onRecordChange (currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.progress
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue (nodeId, value) {
if (canvas.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.setPercentage(value, 30)
}
}
+47
View File
@@ -0,0 +1,47 @@
function newNodesRunning () {
const MODULE_NAME = 'Nodes Running'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize () {
hiriarchyMap = undefined
}
function initialize (pRootNode) {
let rootNode = canvas.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = getHiriarchyMap(rootNode)
}
function onRecordChange (currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.running
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue (nodeId, value) {
if (canvas.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.runningAtBackend()
}
}
+47
View File
@@ -0,0 +1,47 @@
function newNodesStatus () {
const MODULE_NAME = 'Nodes Status'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize () {
hiriarchyMap = undefined
}
function initialize (pRootNode) {
let rootNode = canvas.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = getHiriarchyMap(rootNode)
}
function onRecordChange (currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.status
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue (nodeId, value) {
if (canvas.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.setStatus(value, 30)
}
}
+47
View File
@@ -0,0 +1,47 @@
function newNodesValues () {
const MODULE_NAME = 'Nodes Values'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize () {
hiriarchyMap = undefined
}
function initialize (pRootNode) {
let rootNode = canvas.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = getHiriarchyMap(rootNode)
}
function onRecordChange (currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.values
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue (nodeId, value) {
if (canvas.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.setValue(value, 1)
}
}
@@ -245,13 +245,14 @@ function newPlotter () {
function draw () {
try {
thisObject.container.frame.draw()
plotChart()
plot()
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] draw -> err = ' + err.stack) }
}
}
function recalculate () {
if (canvas.chartingSpace.visible !== true) { return }
try {
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
recalculateUsingMarketFiles()
@@ -277,8 +278,8 @@ function newPlotter () {
let record = {}
for (let j = 0; j < recordDefinition.properties.length; j++) {
let property = recordDefinition.properties[j]
if (property.code.isCalculated !== true) {
record[property.code.codeName] = dataFile[i][j]
if (property.config.isCalculated !== true) {
record[property.config.codeName] = dataFile[i][j]
}
}
@@ -310,7 +311,7 @@ function newPlotter () {
timeFrame: timeFrame,
ONE_DAY_IN_MILISECONDS: ONE_DAY_IN_MILISECONDS
}
let variable = {} // This is the structure where the user will define its own variables that will be shared across different code blocks and formulas.
let variable = {} // This is the structure where the user will define its own variables that will be shared across different config blocks and formulas.
let results = []
/* This is Initialization Code */
@@ -345,13 +346,13 @@ function newPlotter () {
/* For each calculated property we apply its formula */
for (let j = 0; j < recordDefinition.properties.length; j++) {
let property = recordDefinition.properties[j]
if (property.code.isCalculated === true) {
if (property.config.isCalculated === true) {
if (property.formula !== undefined) {
if (property.formula.code !== undefined) {
try {
let newValue = eval(property.formula.code)
let currentRecord = product
currentRecord[property.code.codeName] = newValue
currentRecord[property.config.codeName] = newValue
} catch (err) {
logger.write('[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. Error = ' + err.stack.stack)
logger.write('[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. product = ' + JSON.stringify(product))
@@ -489,13 +490,10 @@ function newPlotter () {
}
}
function plotChart () {
function plot () {
try {
/* Clean the pannel at places where there is no record. */
let currentRecord = {
data: undefined
}
thisObject.container.eventHandler.raiseEvent('Current Record Changed', currentRecord)
thisObject.container.eventHandler.raiseEvent('Current Record Changed', undefined)
for (let i = 0; i < records.length; i++) {
let record = records[i]
@@ -505,7 +503,7 @@ function newPlotter () {
To enable that we need to link all records to the previous one in this way.
*/
if (i == 0) {
record.previous = record
record.previous = {} // this way it wont be undefined
} else {
record.previous = records[i - 1]
}
@@ -539,11 +537,7 @@ function newPlotter () {
let atMousePosition = false
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
atMousePosition = true
let currentRecord = {
data: record
}
thisObject.container.eventHandler.raiseEvent('Current Record Changed', currentRecord)
thisObject.container.eventHandler.raiseEvent('Current Record Changed', record)
}
/* If there is code we execute it now. */
@@ -596,6 +590,7 @@ function newPlotter () {
record.dataPoints = dataPoints
}
/* Here we are going to plot all the polygons. */
for (let j = 0; j < productDefinition.referenceParent.shapes.polygons.length; j++) {
let polygon = productDefinition.referenceParent.shapes.polygons[j]
/* We will check if we need to plot this Polygon or not. */
@@ -622,9 +617,9 @@ function newPlotter () {
} else {
/* Get the default style if exists */
if (polygon.polygonBody.style !== undefined) {
if (polygon.polygonBody.style.code !== undefined) {
if (polygon.polygonBody.style.code.default !== undefined) {
let bodyStyle = polygon.polygonBody.style.code.default
if (polygon.polygonBody.style.config !== undefined) {
if (polygon.polygonBody.style.config.default !== undefined) {
let bodyStyle = polygon.polygonBody.style.config.default
if (bodyStyle.opacity !== undefined) { fillStyle.opacity = bodyStyle.opacity }
if (bodyStyle.paletteColor !== undefined) { fillStyle.paletteColor = eval(bodyStyle.paletteColor) }
}
@@ -637,7 +632,7 @@ function newPlotter () {
let value = eval(condition.code)
if (value === true) {
if (condition.style !== undefined) {
let bodyStyle = condition.style.code
let bodyStyle = condition.style.config
if (bodyStyle.opacity !== undefined) { fillStyle.opacity = bodyStyle.opacity }
if (bodyStyle.paletteColor !== undefined) { fillStyle.paletteColor = eval(bodyStyle.paletteColor) }
}
@@ -646,8 +641,8 @@ function newPlotter () {
}
/* Get the atMousePosition style if exists */
if (polygon.polygonBody.style !== undefined) {
if (polygon.polygonBody.style.code.atMousePosition !== undefined) {
let atMousePositionStyleDefinition = polygon.polygonBody.style.code.atMousePosition
if (polygon.polygonBody.style.config.atMousePosition !== undefined) {
let atMousePositionStyleDefinition = polygon.polygonBody.style.config.atMousePosition
let atMousePositionStyle = {}
if (atMousePositionStyleDefinition.opacity !== undefined) { atMousePositionStyle.opacity = atMousePositionStyleDefinition.opacity }
if (atMousePositionStyleDefinition.paletteColor !== undefined) { atMousePositionStyle.paletteColor = eval(atMousePositionStyleDefinition.paletteColor) }
@@ -677,9 +672,9 @@ function newPlotter () {
} else {
/* Get the default style if exists */
if (polygon.polygonBorder.style !== undefined) {
if (polygon.polygonBorder.style.code !== undefined) {
if (polygon.polygonBorder.style.code.default !== undefined) {
let borderStyle = polygon.polygonBorder.style.code.default
if (polygon.polygonBorder.style.config !== undefined) {
if (polygon.polygonBorder.style.config.default !== undefined) {
let borderStyle = polygon.polygonBorder.style.config.default
if (borderStyle.opacity !== undefined) { strokeStyle.opacity = borderStyle.opacity }
if (borderStyle.paletteColor !== undefined) { strokeStyle.paletteColor = eval(borderStyle.paletteColor) }
if (borderStyle.lineWidth !== undefined) { strokeStyle.lineWidth = borderStyle.lineWidth }
@@ -694,7 +689,7 @@ function newPlotter () {
let value = eval(condition.code)
if (value === true) {
if (condition.style !== undefined) {
let borderStyle = condition.style.code
let borderStyle = condition.style.config
if (borderStyle.opacity !== undefined) { strokeStyle.opacity = borderStyle.opacity }
if (borderStyle.paletteColor !== undefined) { strokeStyle.paletteColor = eval(borderStyle.paletteColor) }
if (borderStyle.lineWidth !== undefined) { strokeStyle.lineWidth = borderStyle.lineWidth }
@@ -705,8 +700,8 @@ function newPlotter () {
}
/* Get the atMousePosition style if exists */
if (polygon.polygonBorder.style !== undefined) {
if (polygon.polygonBorder.style.code.atMousePosition !== undefined) {
let atMousePositionStyleDefinition = polygon.polygonBorder.style.code.atMousePosition
if (polygon.polygonBorder.style.config.atMousePosition !== undefined) {
let atMousePositionStyleDefinition = polygon.polygonBorder.style.config.atMousePosition
let atMousePositionStyle = {}
if (atMousePositionStyleDefinition.opacity !== undefined) { atMousePositionStyle.opacity = atMousePositionStyleDefinition.opacity }
if (atMousePositionStyleDefinition.paletteColor !== undefined) { atMousePositionStyle.paletteColor = eval(atMousePositionStyleDefinition.paletteColor) }
@@ -782,6 +777,79 @@ function newPlotter () {
browserCanvasContext.stroke()
}
}
/* Here we are going to plot images. */
for (let j = 0; j < productDefinition.referenceParent.shapes.images.length; j++) {
let image = productDefinition.referenceParent.shapes.images[j]
if (image.imagePosition === undefined) { continue }
if (image.imagePosition.referenceParent === undefined) { continue }
if (image.imageCondition !== undefined) {
let mustPlot = eval(image.imageCondition.code)
if (mustPlot !== true) { continue }
}
let imageName = ''
let imageSize = 0
let offsetX = 0
let offsetY = 0
let imagePosition = {x: 0, y: 0}
if (image.config.codeName !== undefined) { imageName = image.config.codeName }
if (image.config.size !== undefined) { imageSize = image.config.size }
if (image.imagePosition.config.offsetX !== undefined) { offsetX = image.imagePosition.config.offsetX }
if (image.imagePosition.config.offsetY !== undefined) { offsetY = image.imagePosition.config.offsetY }
let dataPointObject = dataPoints.get(image.imagePosition.referenceParent.id)
if (dataPointObject === undefined) { continue }
let dataPoint = {
x: dataPointObject.x,
y: dataPointObject.y
}
dataPoint = canvas.chartingSpace.viewport.fitIntoVisibleArea(dataPoint)
dataPoint = thisObject.fitFunction(dataPoint)
imagePosition.x = dataPoint.x
imagePosition.y = dataPoint.y
let imageToDraw = canvas.designSpace.iconCollection.get(imageName)
if (imageToDraw.canDrawIcon === true) {
browserCanvasContext.drawImage(imageToDraw, imagePosition.x - imageSize / 2 + offsetX, imagePosition.y - imageSize / 2 - offsetY, imageSize, imageSize)
}
}
/* Here we are going to plot texts. */
for (let j = 0; j < productDefinition.referenceParent.shapes.texts.length; j++) {
let text = productDefinition.referenceParent.shapes.texts[j]
if (text.textPosition === undefined) { continue }
if (text.textPosition.referenceParent === undefined) { continue }
if (text.textCondition !== undefined) {
let mustPlot = eval(text.textCondition.code)
if (mustPlot !== true) { continue }
}
if (text.textFormula === undefined) { continue }
if (text.textStyle === undefined) { continue }
let value = eval(text.textFormula.code)
let fontSize = 0
let opacity = 0
let paletteColor = UI_COLOR.GREY
let offsetX = 0
let offsetY = 0
let textPosition = {x: 0, y: 0}
if (text.textStyle.config.fontSize !== undefined) { fontSize = text.textStyle.config.fontSize }
if (text.textStyle.config.opacity !== undefined) { opacity = text.textStyle.config.opacity }
if (text.textStyle.config.paletteColor !== undefined) { paletteColor = eval(text.textStyle.config.paletteColor) }
if (text.textPosition.config.offsetX !== undefined) { offsetX = text.textPosition.config.offsetX }
if (text.textPosition.config.offsetY !== undefined) { offsetY = text.textPosition.config.offsetY }
let dataPointObject = dataPoints.get(text.textPosition.referenceParent.id)
if (dataPointObject === undefined) { continue }
let dataPoint = {
x: dataPointObject.x,
y: dataPointObject.y
}
dataPoint = canvas.chartingSpace.viewport.fitIntoVisibleArea(dataPoint)
dataPoint = thisObject.fitFunction(dataPoint)
textPosition.x = dataPoint.x
textPosition.y = dataPoint.y
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = 'rgba(' + paletteColor + ', ' + opacity + ')'
browserCanvasContext.fillText(value, textPosition.x + offsetX, textPosition.y - offsetY)
}
}
if (coordinateSystem.autoMinYScale === true || coordinateSystem.autoMinYScale === true) {
@@ -792,7 +860,7 @@ function newPlotter () {
logged = false
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] plotChart -> err = ' + err.stack) }
if (ERROR_LOG === true) { logger.write('[ERROR] plot -> err = ' + err.stack) }
}
}
@@ -806,11 +874,7 @@ function newPlotter () {
}
function onDragFinished () {
try {
recalculate()
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onDragFinished -> err = ' + err.stack) }
}
recalculate()
}
function onDisplace (event) {
+64
View File
@@ -0,0 +1,64 @@
function newRecordValues () {
const MODULE_NAME = 'Record Values'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let tradingSystem
let tradingEngine
let productDefinition
let productTargetNode
let propertyTargetNodeMap = new Map()
return thisObject
function finalize () {
tradingSystem = undefined
tradingEngine = undefined
productDefinition = undefined
productTargetNode = undefined
propertyTargetNodeMap = undefined
}
function initialize (pTradingSystem, pTradingEngine, pProductDefinition) {
tradingSystem = canvas.designSpace.workspace.getHierarchyHeadsById(pTradingSystem.id)
tradingEngine = canvas.designSpace.workspace.getHierarchyHeadsById(pTradingEngine.id)
productDefinition = pProductDefinition
productTargetNode = eval(productDefinition.config.nodePath)
for (let i = 0; i < productDefinition.record.properties.length; i++) {
let property = productDefinition.record.properties[i]
if (property.config.nodePath !== undefined) {
let propertyRoot = eval(property.config.nodePath)
propertyTargetNodeMap.set(property.id, propertyRoot)
} else {
propertyTargetNodeMap.set(property.id, productTargetNode)
}
}
}
function onRecordChange (currentRecord) {
if (currentRecord === undefined) { return }
for (let i = 0; i < productDefinition.record.properties.length; i++) {
let property = productDefinition.record.properties[i]
let value = currentRecord[property.config.codeName]
let targetNode = propertyTargetNodeMap.get(property.id)
applyValue(targetNode[property.config.codeName], value)
}
}
function applyValue (node, value) {
if (canvas.chartingSpace.visible !== true) { return }
if (node === undefined) { return }
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.setValue(value, 1)
}
}
-2
View File
@@ -29,10 +29,8 @@ function newDashboard () {
for (let i = 0; i < APP_SCHEMA_ARRAY.length; i++) {
let nodeDefinition = APP_SCHEMA_ARRAY[i]
let key = nodeDefinition.type
APP_SCHEMA_MAP.set(key, nodeDefinition)
}
startCanvas()
}
+2 -2
View File
@@ -85,7 +85,7 @@ function newProductStorage (name) {
for (let i = 0; i < product.datasets.length; i++) {
let dataset = product.datasets[i]
switch (dataset.code.type) {
switch (dataset.config.type) {
case 'Market Files': {
dataSetsToLoad++
@@ -122,7 +122,7 @@ function newProductStorage (name) {
}
break
default:
if (ERROR_LOG === true) { logger.write('[WARN] initialize -> dataset with no type defined or type not supported -> dataset.code.type = ' + dataset.code.type) }
if (ERROR_LOG === true) { logger.write('[WARN] initialize -> dataset with no type defined or type not supported -> dataset.config.type = ' + dataset.config.type) }
}
function onMarketFileReady (err, pCaller) {
+19 -19
View File
@@ -255,12 +255,12 @@ function newRateScale () {
function saveObjectState () {
try {
let code = JSON.parse(thisObject.payload.node.code)
code.minValue = coordinateSystem.min.y
code.maxValue = coordinateSystem.max.y
code.autoMinScale = coordinateSystem.autoMinYScale
code.autoMaxScale = coordinateSystem.autoMaxYScale
thisObject.payload.node.code = JSON.stringify(code, null, 4)
let config = JSON.parse(thisObject.payload.node.config)
config.minValue = coordinateSystem.min.y
config.maxValue = coordinateSystem.max.y
config.autoMinScale = coordinateSystem.autoMinYScale
config.autoMaxScale = coordinateSystem.autoMaxYScale
thisObject.payload.node.config = JSON.stringify(config, null, 4)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
@@ -268,29 +268,29 @@ function newRateScale () {
function readObjectState () {
try {
let code = JSON.parse(thisObject.payload.node.code)
let config = JSON.parse(thisObject.payload.node.config)
if (
(isNaN(code.minValue) || code.minValue === null || code.minValue === undefined) ||
(isNaN(code.maxValue) || code.maxValue === null || code.maxValue === undefined)
(isNaN(config.minValue) || config.minValue === null || config.minValue === undefined) ||
(isNaN(config.maxValue) || config.maxValue === null || config.maxValue === undefined)
) {
// not using this value
} else {
if (
thisObject.minValue !== code.minValue ||
thisObject.maxValue !== code.maxValue ||
coordinateSystem.autoMinYScale !== code.autoMinScale ||
coordinateSystem.autoMaxYScale !== code.autoMaxScale
thisObject.minValue !== config.minValue ||
thisObject.maxValue !== config.maxValue ||
coordinateSystem.autoMinYScale !== config.autoMinScale ||
coordinateSystem.autoMaxYScale !== config.autoMaxScale
) {
thisObject.minValue = code.minValue
thisObject.maxValue = code.maxValue
thisObject.minValue = config.minValue
thisObject.maxValue = config.maxValue
coordinateSystem.min.y = thisObject.minValue
coordinateSystem.max.y = thisObject.maxValue
if (code.autoMinScale !== undefined && (code.autoMinScale === true || code.autoMinScale === false) && code.autoMaxScale !== undefined && (code.autoMaxScale === true || code.autoMaxScale === false)) {
coordinateSystem.autoMinYScale = code.autoMinScale
coordinateSystem.autoMaxYScale = code.autoMaxScale
autoScaleButton.setStatus(code.autoMinScale, code.autoMaxScale)
if (config.autoMinScale !== undefined && (config.autoMinScale === true || config.autoMinScale === false) && config.autoMaxScale !== undefined && (config.autoMaxScale === true || config.autoMaxScale === false)) {
coordinateSystem.autoMinYScale = config.autoMinScale
coordinateSystem.autoMaxYScale = config.autoMaxScale
autoScaleButton.setStatus(config.autoMinScale, config.autoMaxScale)
}
coordinateSystem.recalculateScale()
+6 -6
View File
@@ -313,9 +313,9 @@ function newTimeFrameScale () {
function saveObjectState () {
try {
let code = JSON.parse(thisObject.payload.node.code)
code.value = timeFrameLabel
thisObject.payload.node.code = JSON.stringify(code)
let config = JSON.parse(thisObject.payload.node.config)
config.value = timeFrameLabel
thisObject.payload.node.config = JSON.stringify(config)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
@@ -323,14 +323,14 @@ function newTimeFrameScale () {
function readObjectState () {
try {
let code = JSON.parse(thisObject.payload.node.code)
if (code.value !== timeFrameLabel) {
let config = JSON.parse(thisObject.payload.node.config)
if (config.value !== timeFrameLabel) {
let found = false
for (let i = 0; i < timeFramesMasterArray.length; i++) {
let timeFrameArray = timeFramesMasterArray[i]
for (let j = 0; j < timeFrameArray.length; j++) {
let record = timeFrameArray[j]
if (code.value === record[1]) {
if (config.value === record[1]) {
filePeriodIndex = i
timeFrameIndex = j
found = true
+16 -16
View File
@@ -172,12 +172,12 @@ function newTimeScale () {
function saveObjectState () {
try {
let code = JSON.parse(thisObject.payload.node.code)
code.fromDate = (new Date(coordinateSystem.min.x)).toISOString()
code.toDate = (new Date(coordinateSystem.max.x)).toISOString()
code.autoMinScale = coordinateSystem.autoMinXScale
code.autoMaxScale = coordinateSystem.autoMaxXScale
thisObject.payload.node.code = JSON.stringify(code, null, 4)
let config = JSON.parse(thisObject.payload.node.config)
config.fromDate = (new Date(coordinateSystem.min.x)).toISOString()
config.toDate = (new Date(coordinateSystem.max.x)).toISOString()
config.autoMinScale = coordinateSystem.autoMinXScale
config.autoMaxScale = coordinateSystem.autoMaxXScale
thisObject.payload.node.config = JSON.stringify(config, null, 4)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
@@ -185,24 +185,24 @@ function newTimeScale () {
function readObjectState () {
try {
let code = JSON.parse(thisObject.payload.node.code)
let config = JSON.parse(thisObject.payload.node.config)
if (
(isNaN(Date.parse(code.fromDate)) || code.fromDate === null || code.fromDate === undefined) ||
(isNaN(Date.parse(code.toDate)) || code.toDate === null || code.toDate === undefined)
(isNaN(Date.parse(config.fromDate)) || config.fromDate === null || config.fromDate === undefined) ||
(isNaN(Date.parse(config.toDate)) || config.toDate === null || config.toDate === undefined)
) {
// not using this value
} else {
if (thisObject.fromDate !== Date.parse(code.fromDate) || thisObject.toDate !== Date.parse(code.toDate)) {
thisObject.fromDate = Date.parse(code.fromDate)
thisObject.toDate = Date.parse(code.toDate)
if (thisObject.fromDate !== Date.parse(config.fromDate) || thisObject.toDate !== Date.parse(config.toDate)) {
thisObject.fromDate = Date.parse(config.fromDate)
thisObject.toDate = Date.parse(config.toDate)
coordinateSystem.min.x = thisObject.fromDate
coordinateSystem.max.x = thisObject.toDate
if (code.autoMinScale !== undefined && (code.autoMinScale === true || code.autoMinScale === false) && code.autoMaxScale !== undefined && (code.autoMaxScale === true || code.autoMaxScale === false)) {
coordinateSystem.autoMinXScale = code.autoMinScale
coordinateSystem.autoMaxXScale = code.autoMaxScale
autoScaleButton.setStatus(code.autoMinScale, code.autoMaxScale)
if (config.autoMinScale !== undefined && (config.autoMinScale === true || config.autoMinScale === false) && config.autoMaxScale !== undefined && (config.autoMaxScale === true || config.autoMaxScale === false)) {
coordinateSystem.autoMinXScale = config.autoMinScale
coordinateSystem.autoMaxXScale = config.autoMaxScale
autoScaleButton.setStatus(config.autoMinScale, config.autoMaxScale)
}
coordinateSystem.recalculateScale()
}
+7 -1
View File
@@ -285,7 +285,13 @@ function newDesignSpace () {
'arrangement-vertical-right',
'arrangement-vertical-left',
'arrangement-concave',
'move-to-phase-event'
'move-to-phase-event',
'open-execution',
'move-order',
'market-order',
'limit-order',
'execution-algorithm',
'cancel-order'
]
for (let i = 0; i < iconsNames.length; i++) {
+2 -2
View File
@@ -50,14 +50,14 @@ function newPanelsSpace () {
}
case 'Plotter Panel':
{
if (pParameters.panelNode.code.isLegacy !== true) {
if (pParameters.panelNode.config.isLegacy !== true) {
panel = newPlotterPanel()
panel.fitFunction = canvas.chartingSpace.fitFunction
panel.container.isVisibleFunction = canvas.chartingSpace.isThisPointVisible
panel.session = pSession
panel.initialize(pParameters.panelNode)
} else {
panel = getNewPlotterPanel(pParameters.dataMine, pParameters.plotterCodeName, pParameters.moduleCodeName, pParameters.panelNode.code.codeName)
panel = getNewPlotterPanel(pParameters.dataMine, pParameters.plotterCodeName, pParameters.moduleCodeName, pParameters.panelNode.config.codeName)
panel.fitFunction = canvas.chartingSpace.fitFunction
panel.container.isVisibleFunction = canvas.chartingSpace.isThisPointVisible
panel.session = pSession
+1 -1
View File
@@ -125,7 +125,7 @@ function newSplashScreen () {
fontSize = 35
title = 'Beta 5'
title = 'Beta 6'
titlePoint = {
x: thisObject.container.frame.width / 2 - title.length / 2 * fontSize * FONT_ASPECT_RATIO - 20,
+3 -241
View File
@@ -1,25 +1,6 @@
function drawContainerBackground (container, color, opacity, fitFunction) {
let fromPoint = {
x: 0,
y: 0
}
let toPoint = {
x: container.frame.width,
y: container.frame.height
}
fromPoint = transformThisPoint(fromPoint, container)
toPoint = transformThisPoint(toPoint, container)
fromPoint = fitFunction(fromPoint)
toPoint = fitFunction(toPoint)
browserCanvasContext.beginPath()
browserCanvasContext.rect(fromPoint.x, fromPoint.y, toPoint.x - fromPoint.x, toPoint.y - fromPoint.y)
browserCanvasContext.fillStyle = 'rgba(' + color + ', ' + opacity + ')'
browserCanvasContext.closePath()
browserCanvasContext.fill()
function getNodeDefinition (node) {
let key = node.type
return APP_SCHEMA_MAP.get(key)
}
function dynamicDecimals (value, minDecimals) {
@@ -38,50 +19,6 @@ function dynamicDecimals (value, minDecimals) {
return returnValue
}
function savePropertyAtNodeConfig (payload, propertyName, value) {
try {
let code = JSON.parse(payload.node.code)
code[propertyName] = value
payload.node.code = JSON.stringify(code, null, 4)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function loadPropertyFromNodeConfig (payload, propertyName) {
try {
let code = JSON.parse(payload.node.code)
return code[propertyName]
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function saveFrame (payload, frame) {
payload.frame = {
position: {
x: frame.position.x,
y: frame.position.y
},
width: frame.width,
height: frame.height,
radius: frame.radius
}
}
function loadFrame (payload, frame) {
if (payload.node.savedPayload !== undefined) {
if (payload.node.savedPayload.frame !== undefined) {
frame.position.x = payload.node.savedPayload.frame.position.x
frame.position.y = payload.node.savedPayload.frame.position.y
frame.width = payload.node.savedPayload.frame.width
frame.height = payload.node.savedPayload.frame.height
frame.radius = payload.node.savedPayload.frame.radius
payload.node.savedPayload.frame = undefined
}
}
}
function convertTimeFrameToName (pTimeFrame) {
for (let i = 0; i < dailyFilePeriods.length; i++) {
let period = dailyFilePeriods[i]
@@ -98,84 +35,6 @@ function convertTimeFrameToName (pTimeFrame) {
}
}
function downloadText (filename, text) {
let element = document.createElement('a')
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
}
function downloadCanvas (filename, canvasToUse) {
let data = canvasToUse.toDataURL('image/png', 1)
/* Change MIME type to trick the browser to downlaod the file instead of displaying it */
data = data.replace(/^data:image\/[^;]*/, 'data:application/octet-stream')
/* In addition to <a>'s "download" attribute, you can define HTTP-style headers */
data = data.replace(/^data:application\/octet-stream/, 'data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=' + filename + '.png')
let element = document.createElement('a')
element.setAttribute('href', data)
element.setAttribute('download', filename + '.PNG')
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
};
function downloadPanorama (filename) {
let INITIAL_WIDTH = 800
let FINAL_WIDTH = browserCanvas.width - INITIAL_WIDTH
if (ARE_WE_RECORDING_A_MARKET_PANORAMA === false) {
/* We start recording the panorame. */
ARE_WE_RECORDING_A_MARKET_PANORAMA = true
marketPanoramaCanvas = document.createElement('canvas')
marketPanoramaCanvas.width = INITIAL_WIDTH * 50
marketPanoramaCanvas.height = browserCanvas.height
marketPanoramaCanvas.getContext('2d').drawImage(browserCanvas, 0, 0, INITIAL_WIDTH, browserCanvas.height, 0, 0, INITIAL_WIDTH, browserCanvas.height)
CURRENT_PANORAMA_POSITION = INITIAL_WIDTH
} else {
/* We stop recording and download the resulting image. */
ARE_WE_RECORDING_A_MARKET_PANORAMA = false
marketPanoramaCanvas.getContext('2d').drawImage(browserCanvas, browserCanvas.width - FINAL_WIDTH, 0, FINAL_WIDTH, browserCanvas.height, CURRENT_PANORAMA_POSITION, 0, FINAL_WIDTH, browserCanvas.height)
let finalResultCanvas = document.createElement('canvas')
finalResultCanvas.width = CURRENT_PANORAMA_POSITION + FINAL_WIDTH
finalResultCanvas.height = browserCanvas.height
finalResultCanvas.getContext('2d').drawImage(marketPanoramaCanvas, 0, 0, finalResultCanvas.width, browserCanvas.height, 0, 0, finalResultCanvas.width, browserCanvas.height)
downloadCanvas(filename, finalResultCanvas)
marketPanoramaCanvas = undefined
}
}
function addToMarketPanorama () {
let SECTION_WIDTH = 80 * 2
let INITIAL_POSITION = 800 - SECTION_WIDTH
marketPanoramaCanvas.getContext('2d').drawImage(browserCanvas, INITIAL_POSITION, 0, SECTION_WIDTH, browserCanvas.height, CURRENT_PANORAMA_POSITION, 0, SECTION_WIDTH, browserCanvas.height)
CURRENT_PANORAMA_POSITION = CURRENT_PANORAMA_POSITION + SECTION_WIDTH
}
function transformThisPoint (point, container) {
/* We make the point relative to the current frame */
point = container.frame.frameThisPoint(point)
/* We pass this point through the canvas.chartingSpace.viewport lends, meaning we apply the canvas.chartingSpace.viewport zoom and displacement. */
point = canvas.chartingSpace.viewport.transformThisPoint(point)
return point
}
function unTransformThisPoint (point, container) {
point = canvas.chartingSpace.viewport.unTransformThisPoint(point)
point = container.frame.unframeThisPoint(point)
return point
}
function nextPorwerOf10 (number) {
for (let i = -10; i <= 10; i++) {
if (number < Math.pow(10, i)) {
@@ -189,59 +48,6 @@ function pad (str, max) {
return str.length < max ? pad('0' + str, max) : str
}
function getDateFromPointAtBrowserCanvas (point, container, coordinateSystem) {
point = unTransformThisPoint(point, container)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
let date = new Date(point.x)
return date
}
function getDateFromPointAtChartsSpace (point, container, coordinateSystem) {
point = container.frame.unframeThisPoint(point)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
let date = new Date(point.x)
return date
}
function getDateFromPointAtContainer (point, container, coordinateSystem) {
point = coordinateSystem.unInverseTransform(point, container.frame.height)
let date = new Date(point.x)
return date
}
function getRateFromPointAtBrowserCanvas (point, container, coordinateSystem) {
point = unTransformThisPoint(point, container)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.y
}
function getRateFromPointAtChartingSpace (point, container, coordinateSystem) {
point = container.frame.unframeThisPoint(point)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.y
}
function getRateFromPointAtContainer (point, container, coordinateSystem) {
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.y
}
function getMilisecondsFromPoint (point, container, coordinateSystem) {
point = unTransformThisPoint(point, container)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.x
}
function moveToUserPosition (container, currentDate, currentRate, coordinateSystem, ignoreX, ignoreY, mousePosition, fitFunction) {
let targetPoint = {
x: currentDate.valueOf(),
@@ -276,50 +82,6 @@ function removeTime (datetime) {
return dateOnly
}
function printLabel (labelToPrint, x, y, opacity, fontSize, color, center, container, fitFunction, noDecimals, fixedDecimals) {
if (labelToPrint === undefined) { return }
let labelPoint
if (color === undefined) { color = UI_COLOR.DARK }
if (fontSize === undefined) { fontSize = 10 };
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
let label = labelToPrint
if (isNaN(label) === false && label !== '') {
if (fixedDecimals !== true) {
label = dynamicDecimals(labelToPrint)
}
label = label.toLocaleString()
if (noDecimals === true) {
label = Math.trunc(label)
}
}
let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO
if (center === true) {
labelPoint = {
x: x - xOffset,
y: y
}
} else {
labelPoint = {
x: x,
y: y
}
}
if (container !== undefined) {
labelPoint = container.frame.frameThisPoint(labelPoint)
}
if (fitFunction !== undefined) {
labelPoint = fitFunction(labelPoint)
}
browserCanvasContext.fillStyle = 'rgba(' + color + ', ' + opacity + ')'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
function newUniqueId () {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8)
@@ -0,0 +1,18 @@
function transformThisPoint (point, container) {
/* We make the point relative to the current frame */
point = container.frame.frameThisPoint(point)
/* We pass this point through the canvas.chartingSpace.viewport lends, meaning we apply the canvas.chartingSpace.viewport zoom and displacement. */
point = canvas.chartingSpace.viewport.transformThisPoint(point)
return point
}
function unTransformThisPoint (point, container) {
point = canvas.chartingSpace.viewport.unTransformThisPoint(point)
point = container.frame.unframeThisPoint(point)
return point
}
@@ -0,0 +1,53 @@
function getDateFromPointAtBrowserCanvas (point, container, coordinateSystem) {
point = unTransformThisPoint(point, container)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
let date = new Date(point.x)
return date
}
function getDateFromPointAtChartsSpace (point, container, coordinateSystem) {
point = container.frame.unframeThisPoint(point)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
let date = new Date(point.x)
return date
}
function getDateFromPointAtContainer (point, container, coordinateSystem) {
point = coordinateSystem.unInverseTransform(point, container.frame.height)
let date = new Date(point.x)
return date
}
function getRateFromPointAtBrowserCanvas (point, container, coordinateSystem) {
point = unTransformThisPoint(point, container)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.y
}
function getRateFromPointAtChartingSpace (point, container, coordinateSystem) {
point = container.frame.unframeThisPoint(point)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.y
}
function getRateFromPointAtContainer (point, container, coordinateSystem) {
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.y
}
function getMilisecondsFromPoint (point, container, coordinateSystem) {
point = unTransformThisPoint(point, container)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.x
}
+58
View File
@@ -0,0 +1,58 @@
function downloadText (filename, text) {
let element = document.createElement('a')
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
}
function downloadCanvas (filename, canvasToUse) {
let data = canvasToUse.toDataURL('image/png', 1)
/* Change MIME type to trick the browser to downlaod the file instead of displaying it */
data = data.replace(/^data:image\/[^;]*/, 'data:application/octet-stream')
/* In addition to <a>'s "download" attribute, you can define HTTP-style headers */
data = data.replace(/^data:application\/octet-stream/, 'data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=' + filename + '.png')
let element = document.createElement('a')
element.setAttribute('href', data)
element.setAttribute('download', filename + '.PNG')
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
};
function downloadPanorama (filename) {
let INITIAL_WIDTH = 800
let FINAL_WIDTH = browserCanvas.width - INITIAL_WIDTH
if (ARE_WE_RECORDING_A_MARKET_PANORAMA === false) {
/* We start recording the panorame. */
ARE_WE_RECORDING_A_MARKET_PANORAMA = true
marketPanoramaCanvas = document.createElement('canvas')
marketPanoramaCanvas.width = INITIAL_WIDTH * 50
marketPanoramaCanvas.height = browserCanvas.height
marketPanoramaCanvas.getContext('2d').drawImage(browserCanvas, 0, 0, INITIAL_WIDTH, browserCanvas.height, 0, 0, INITIAL_WIDTH, browserCanvas.height)
CURRENT_PANORAMA_POSITION = INITIAL_WIDTH
} else {
/* We stop recording and download the resulting image. */
ARE_WE_RECORDING_A_MARKET_PANORAMA = false
marketPanoramaCanvas.getContext('2d').drawImage(browserCanvas, browserCanvas.width - FINAL_WIDTH, 0, FINAL_WIDTH, browserCanvas.height, CURRENT_PANORAMA_POSITION, 0, FINAL_WIDTH, browserCanvas.height)
let finalResultCanvas = document.createElement('canvas')
finalResultCanvas.width = CURRENT_PANORAMA_POSITION + FINAL_WIDTH
finalResultCanvas.height = browserCanvas.height
finalResultCanvas.getContext('2d').drawImage(marketPanoramaCanvas, 0, 0, finalResultCanvas.width, browserCanvas.height, 0, 0, finalResultCanvas.width, browserCanvas.height)
downloadCanvas(filename, finalResultCanvas)
marketPanoramaCanvas = undefined
}
}
function addToMarketPanorama () {
let SECTION_WIDTH = 80 * 2
let INITIAL_POSITION = 800 - SECTION_WIDTH
marketPanoramaCanvas.getContext('2d').drawImage(browserCanvas, INITIAL_POSITION, 0, SECTION_WIDTH, browserCanvas.height, CURRENT_PANORAMA_POSITION, 0, SECTION_WIDTH, browserCanvas.height)
CURRENT_PANORAMA_POSITION = CURRENT_PANORAMA_POSITION + SECTION_WIDTH
}
@@ -150,3 +150,72 @@ function drawIcon (icon, xFactor, yFactor, xOffset, yOffset, imageSize, containe
}
}
}
function drawContainerBackground (container, color, opacity, fitFunction) {
let fromPoint = {
x: 0,
y: 0
}
let toPoint = {
x: container.frame.width,
y: container.frame.height
}
fromPoint = transformThisPoint(fromPoint, container)
toPoint = transformThisPoint(toPoint, container)
fromPoint = fitFunction(fromPoint)
toPoint = fitFunction(toPoint)
browserCanvasContext.beginPath()
browserCanvasContext.rect(fromPoint.x, fromPoint.y, toPoint.x - fromPoint.x, toPoint.y - fromPoint.y)
browserCanvasContext.fillStyle = 'rgba(' + color + ', ' + opacity + ')'
browserCanvasContext.closePath()
browserCanvasContext.fill()
}
function printLabel (labelToPrint, x, y, opacity, fontSize, color, center, container, fitFunction, noDecimals, fixedDecimals) {
if (labelToPrint === undefined) { return }
let labelPoint
if (color === undefined) { color = UI_COLOR.DARK }
if (fontSize === undefined) { fontSize = 10 };
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
let label = labelToPrint
if (isNaN(label) === false && label !== '') {
if (fixedDecimals !== true) {
label = dynamicDecimals(labelToPrint)
}
label = label.toLocaleString()
if (noDecimals === true) {
label = Math.trunc(label)
}
}
let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO
if (center === true) {
labelPoint = {
x: x - xOffset,
y: y
}
} else {
labelPoint = {
x: x,
y: y
}
}
if (container !== undefined) {
labelPoint = container.frame.frameThisPoint(labelPoint)
}
if (fitFunction !== undefined) {
labelPoint = fitFunction(labelPoint)
}
browserCanvasContext.fillStyle = 'rgba(' + color + ', ' + opacity + ')'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
+47
View File
@@ -0,0 +1,47 @@
/*
This function scans a node hiriatchy recursively and creates a Map by Id of all the nodes of it.
*/
function getHiriarchyMap (rootNode) {
let hiriatchyMap = new Map()
evalNode(rootNode)
return hiriatchyMap
function evalNode (node) {
if (node === undefined) { return }
hiriatchyMap.set(node.id, node)
/* Now we go down through all this node children */
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
if (nodeDefinition === undefined) { return }
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (node[property.name] !== undefined) {
evalNode(node[property.name])
}
previousPropertyName = property.name
}
break
}
case 'array': {
if (node[property.name] !== undefined) {
let nodePropertyArray = node[property.name]
for (let m = 0; m < nodePropertyArray.length; m++) {
evalNode(nodePropertyArray[m])
}
}
break
}
}
}
}
}
}
+24
View File
@@ -0,0 +1,24 @@
function saveFrame (payload, frame) {
payload.frame = {
position: {
x: frame.position.x,
y: frame.position.y
},
width: frame.width,
height: frame.height,
radius: frame.radius
}
}
function loadFrame (payload, frame) {
if (payload.node.savedPayload !== undefined) {
if (payload.node.savedPayload.frame !== undefined) {
frame.position.x = payload.node.savedPayload.frame.position.x
frame.position.y = payload.node.savedPayload.frame.position.y
frame.width = payload.node.savedPayload.frame.width
frame.height = payload.node.savedPayload.frame.height
frame.radius = payload.node.savedPayload.frame.radius
payload.node.savedPayload.frame = undefined
}
}
}
+18
View File
@@ -0,0 +1,18 @@
function savePropertyAtNodeConfig (payload, propertyName, value) {
try {
let config = JSON.parse(payload.node.config)
config[propertyName] = value
payload.node.config = JSON.stringify(config, null, 4)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function loadPropertyFromNodeConfig (payload, propertyName) {
try {
let config = JSON.parse(payload.node.config)
return config[propertyName]
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
+3 -3
View File
@@ -55,7 +55,7 @@ function newDailyFiles () {
fileCloud.initialize(pBot, pHost, pPort)
/* Some Validations */
if (pDataset.code.validTimeFrames === undefined) {
if (pDataset.config.validTimeFrames === undefined) {
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = Can not initialize Market Files for bot ' + pBot.name) }
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = You need to define validTimeFrames at the Dataset config. ') }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
@@ -111,7 +111,7 @@ function newDailyFiles () {
let periodTime = dailyFilePeriods[i][0]
let periodName = dailyFilePeriods[i][1]
if (pDataset.code.validTimeFrames.includes(periodName) === true) {
if (pDataset.config.validTimeFrames.includes(periodName) === true) {
let fileCursor = newFileCursor()
fileCursor.eventHandler = thisObject.eventHandler // We share our event handler with each file cursor, so that they can raise events there when files are changed.s
fileCursor.initialize(fileCloud, pDataMine, pBot, pSession, pProduct, pDataset, exchange, pMarket, periodName, periodTime, pDatetime, pTimeFrame, beginDateRange, endDateRange, pEventsServerClient, onInitialized)
@@ -147,7 +147,7 @@ function newDailyFiles () {
let periodTime = dailyFilePeriods[i][0]
let periodName = dailyFilePeriods[i][1]
if (pDataset.code.validTimeFrames.includes(periodName) === true) {
if (pDataset.config.validTimeFrames.includes(periodName) === true) {
let fileCursor = fileCursors.get(periodTime)
fileCursor.reload(onFileReceived)
}
+14 -14
View File
@@ -36,18 +36,18 @@ function newFileCloud () {
function getFileRecursively (pRetryCounter, pDataMine, pBot, pSession, pProduct, pDataset, pExchange, pMarket, pPeriodName, pDatetime, pSequence, pDataRange, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write('[INFO] getFile -> getFileRecursively -> Entering function.') }
if (INFO_LOG === true) { logger.write('[INFO] getFile -> getFileRecursively -> key = ' + pDataMine.code.codeName + '-' + pBot.code.codeName + '-' + pDataset.code.filePath + '-' + pDataset.code.fileName) }
if (INFO_LOG === true) { logger.write('[INFO] getFile -> getFileRecursively -> key = ' + pDataMine.config.codeName + '-' + pBot.config.codeName + '-' + pDataset.config.filePath + '-' + pDataset.config.fileName) }
let fileName
let filePath
if (pDataRange === undefined) {
fileName = pDataset.code.fileName
filePath = pDataset.code.filePath
fileName = pDataset.config.fileName
filePath = pDataset.config.filePath
} else {
if (pDataset.code.dataRange !== undefined) {
fileName = pDataset.code.dataRange.fileName
filePath = pDataset.code.dataRange.filePath
if (pDataset.config.dataRange !== undefined) {
fileName = pDataset.config.dataRange.fileName
filePath = pDataset.config.dataRange.filePath
} else {
let customErr = {
result: GLOBAL.CUSTOM_FAIL_RESPONSE.result,
@@ -80,19 +80,19 @@ function newFileCloud () {
}
if (pDataMine !== undefined) {
filePath = filePath.replace('@DataMine', pDataMine.code.codeName)
filePath = filePath.replace('@DataMine', pDataMine.config.codeName)
}
if (pBot !== undefined) {
filePath = filePath.replace('@Bot', pBot.code.codeName)
filePath = filePath.replace('@Bot', pBot.config.codeName)
}
if (pSession !== undefined) {
let code
let config
let sessionFolderName = pSession.id
if (pSession.code !== undefined) {
if (pSession.code.folderName !== undefined) {
sessionFolderName = pSession.code.folderName + '-' + pSession.id
if (pSession.config !== undefined) {
if (pSession.config.folderName !== undefined) {
sessionFolderName = pSession.config.folderName + '-' + pSession.id
}
}
filePath = filePath.replace('@Session', sessionFolderName)
@@ -103,8 +103,8 @@ function newFileCloud () {
}
filePath = filePath.replace('@Period', pPeriodName)
filePath = filePath.replace('@Dataset', pDataset.code.codeName)
filePath = filePath.replace('@Product', pProduct.code.codeName)
filePath = filePath.replace('@Dataset', pDataset.config.codeName)
filePath = filePath.replace('@Product', pProduct.config.codeName)
if (pDatetime !== undefined) {
filePath = filePath.replace('@Year', pDatetime.getUTCFullYear())
+2 -2
View File
@@ -108,11 +108,11 @@ function newFileCursor () {
endDateRange = pEndDateRange
eventsServerClient = pEventsServerClient
let key = dataMine.code.codeName + '-' + bot.code.codeName + '-' + product.code.codeName + '-' + dataset.code.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset
let key = dataMine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + dataset.config.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset
let callerId = key + '-' + periodName + newUniqueId()
eventsServerClient.listenToEvent(key, 'Dataset Updated', undefined, callerId, onResponseDataSet, updateFiles)
key = dataMine.code.codeName + '-' + bot.code.codeName + '-' + product.code.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset
key = dataMine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset
callerId = key + '-' + periodName + newUniqueId()
eventsServerClient.listenToEvent(key, 'Data Range Updated', undefined, callerId, onResponseDataRange, updateDataRange)
+1 -1
View File
@@ -88,7 +88,7 @@ function newFileSequence () {
callerId = newUniqueId()
let key = dataMine.code.codeName + '-' + bot.code.codeName + '-' + product.code.codeName + '-' + dataset.code.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset
let key = dataMine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + dataset.config.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset
eventsServerClient.listenToEvent(key, 'Dataset Updated', undefined, callerId, onResponse, updateFiles)
function onResponse (message) {
+4 -4
View File
@@ -95,7 +95,7 @@ function newMarketFiles () {
fileCloud.initialize(pBot, pHost, pPort)
/* Some Validations */
if (dataset.code.validTimeFrames === undefined) {
if (dataset.config.validTimeFrames === undefined) {
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = Can not initialize Market Files for bot ' + pBot.name) }
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = You need to define validTimeFrames at the Dataset config. ') }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
@@ -108,7 +108,7 @@ function newMarketFiles () {
let periodTime = marketFilesPeriods[i][0]
let periodName = marketFilesPeriods[i][1]
if (dataset.code.validTimeFrames.includes(periodName) === true) {
if (dataset.config.validTimeFrames.includes(periodName) === true) {
fileCloud.getFile(dataMine, bot, session, product, dataset, exchange, market, periodName, undefined, undefined, undefined, onFileReceived)
function onFileReceived (err, file) {
@@ -122,7 +122,7 @@ function newMarketFiles () {
}
if (filesLoaded + filesNotLoaded === marketFilesPeriods.length) {
let key = dataMine.code.codeName + '-' + bot.code.codeName + '-' + product.code.codeName + '-' + dataset.code.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset
let key = dataMine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + dataset.config.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset
let callerId = key + '-' + periodName + newUniqueId()
eventsServerClient.listenToEvent(key, 'Dataset Updated', undefined, callerId, onResponse, updateFiles)
@@ -156,7 +156,7 @@ function newMarketFiles () {
let periodTime = marketFilesPeriods[i][0]
let periodName = marketFilesPeriods[i][1]
if (dataset.code.validTimeFrames.includes(periodName) === true) {
if (dataset.config.validTimeFrames.includes(periodName) === true) {
fileCloud.getFile(dataMine, bot, session, product, dataset, exchange, market, periodName, undefined, undefined, undefined, onFileReceived)
function onFileReceived (err, file) {
+1 -1
View File
@@ -30,7 +30,7 @@ function newSingleFile () {
callBackFunction) {
try {
if (INFO_LOG === true) { logger.write('[INFO] initialize -> Entering function.') }
if (INFO_LOG === true) { logger.write('[INFO] initialize -> key = ' + pDataMine.code.codeName + '-' + pBot.code.codeName + '-' + pProduct.code.codeName) }
if (INFO_LOG === true) { logger.write('[INFO] initialize -> key = ' + pDataMine.config.codeName + '-' + pBot.config.codeName + '-' + pProduct.config.codeName) }
let exchange = pExchange
@@ -88,7 +88,7 @@
/* We look first for Exchange Raw Data in order to get when the market starts. */
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs" + "-" + "dataSet.V1";
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
@@ -124,7 +124,7 @@
/* Second, we get the report from Candles Volumes, to know when the marted ends. */
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
@@ -159,7 +159,7 @@
/* Finally we get our own Status Report. */
reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Daily"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
@@ -868,7 +868,7 @@
try {
let reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
let reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Daily"
let thisReport = statusDependencies.statusReports.get(reportKey);
thisReport.file.lastExecution = bot.processDatetime;
@@ -465,7 +465,7 @@
try {
let reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Market" + "-" + "dataSet.V1";
let reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Market"
let thisReport = statusDependencies.statusReports.get(reportKey);
thisReport.file.lastExecution = bot.processDatetime;
@@ -9,7 +9,6 @@
},
"dataMine": "Masters",
"profilePicture": "Bollinger Bands.png",
"dataSetVersion": "dataSet.V1",
"processes": [
{
"name": "Multi-Period-Market",
@@ -52,22 +51,12 @@
{
"dataMine": "Masters",
"bot": "Bollinger-Bands",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Multi-Period-Market",
"dataSetVersion": "dataSet.V1"
"process": "Multi-Period-Market"
},
{
"dataMine": "Masters",
"bot": "Candles-Volumes",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Multi-Period-Market",
"dataSetVersion": "dataSet.V1",
"waitUntilNextUpdate": true
}
]
@@ -113,33 +102,18 @@
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Historic-Trades",
"dataSetVersion": "dataSet.V1"
"process": "Historic-Trades"
},
{
"dataMine": "Masters",
"bot": "Candles-Volumes",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Multi-Period-Daily",
"dataSetVersion": "dataSet.V1",
"waitUntilNextUpdate": true
},
{
"dataMine": "Masters",
"bot": "Bollinger-Bands",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Multi-Period-Daily",
"dataSetVersion": "dataSet.V1"
"process": "Multi-Period-Daily"
}
]
}
@@ -87,7 +87,7 @@ Read the candles and volumes from Exchange Raw Data and produce a file for each
/* We look first for Exchange Raw Data in order to get when the market starts. */
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs" + "-" + "dataSet.V1";
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
@@ -123,7 +123,7 @@ Read the candles and volumes from Exchange Raw Data and produce a file for each
/* Second, we get the report from Exchange Raw Data, to know when the marted ends. */
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs" + "-" + "dataSet.V1"
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
@@ -158,7 +158,7 @@ Read the candles and volumes from Exchange Raw Data and produce a file for each
/* Finally we get our own Status Report. */
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
@@ -786,7 +786,7 @@ Read the candles and volumes from Exchange Raw Data and produce a file for each
try {
let reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
let reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily"
let thisReport = statusDependencies.statusReports.get(reportKey);
thisReport.file.lastExecution = bot.processDatetime;
@@ -96,7 +96,7 @@
/* We look first for Exchange Raw Data in order to get when the market starts. */
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs" + "-" + "dataSet.V1";
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
@@ -132,7 +132,7 @@
/* Second, we get the report from Exchange Raw Data, to know when the marted ends. */
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs" + "-" + "dataSet.V1"
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
@@ -167,7 +167,7 @@
/* Finally we get our own Status Report. */
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Market" + "-" + "dataSet.V1";
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Market"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
@@ -904,7 +904,7 @@
try {
let reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Market" + "-" + "dataSet.V1";
let reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Market"
let thisReport = statusDependencies.statusReports.get(reportKey);
thisReport.file.lastExecution = bot.processDatetime;
@@ -2,14 +2,7 @@
"displayName": "Candles Volumes",
"codeName": "Candles-Volumes",
"type": "Indicator Bot",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"dataMine": "Masters",
"profilePicture": "Candles Volumes.png",
"dataSetVersion": "dataSet.V1",
"processes": [
{
"name": "Multi-Period-Market",
@@ -52,34 +45,19 @@
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Historic-OHLCVs",
"dataSetVersion": "dataSet.V1"
"process": "Historic-OHLCVs"
},
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Historic-OHLCVs",
"dataSetVersion": "dataSet.V1",
"dataSetSection": "Month",
"waitUntilNextUpdate": true
},
{
"dataMine": "Masters",
"bot": "Candles-Volumes",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Multi-Period-Market",
"dataSetVersion": "dataSet.V1"
"process": "Multi-Period-Market"
}
]
},
@@ -124,34 +102,19 @@
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Historic-OHLCVs",
"dataSetVersion": "dataSet.V1"
"process": "Historic-OHLCVs"
},
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Historic-OHLCVs",
"dataSetVersion": "dataSet.V1",
"dataSetSection": "Month",
"waitUntilNextUpdate": true
},
{
"dataMine": "Masters",
"bot": "Candles-Volumes",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Multi-Period-Daily",
"dataSetVersion": "dataSet.V1"
"process": "Multi-Period-Daily"
}
]
}
@@ -57,35 +57,35 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
exchangeId = bot.exchange.toLowerCase()
/* Applying the parameters defined by the user at the Exchange Node Config */
if (bot.exchangeNode.code.API !== undefined) {
for (let i = 0; i < bot.exchangeNode.code.API.length; i++) {
if (bot.exchangeNode.code.API[i].method === 'fetch_ohlcv') {
if (bot.exchangeNode.code.API[i].class !== undefined) {
exchangeId = bot.exchangeNode.code.API[i].class
if (bot.exchangeNode.config.API !== undefined) {
for (let i = 0; i < bot.exchangeNode.config.API.length; i++) {
if (bot.exchangeNode.config.API[i].method === 'fetch_ohlcv') {
if (bot.exchangeNode.config.API[i].class !== undefined) {
exchangeId = bot.exchangeNode.config.API[i].class
}
if (bot.exchangeNode.code.API[i].fetchOHLCVsMethod !== undefined) {
if (bot.exchangeNode.config.API[i].fetchOHLCVsMethod !== undefined) {
options = {
'fetchOHLCVsMethod': bot.exchangeNode.code.API[i].fetchOHLCVsMethod
'fetchOHLCVsMethod': bot.exchangeNode.config.API[i].fetchOHLCVsMethod
}
}
if (bot.exchangeNode.code.API[i].firstId !== undefined) {
firstId = bot.exchangeNode.code.API[i].firstId
if (bot.exchangeNode.config.API[i].firstId !== undefined) {
firstId = bot.exchangeNode.config.API[i].firstId
}
if (bot.exchangeNode.code.API[i].rateLimit !== undefined) {
rateLimit = bot.exchangeNode.code.API[i].rateLimit
if (bot.exchangeNode.config.API[i].rateLimit !== undefined) {
rateLimit = bot.exchangeNode.config.API[i].rateLimit
}
if (bot.exchangeNode.code.API[i].hostname !== undefined) {
hostname = bot.exchangeNode.code.API[i].hostname
if (bot.exchangeNode.config.API[i].hostname !== undefined) {
hostname = bot.exchangeNode.config.API[i].hostname
}
if (bot.exchangeNode.code.API[i].fetchType !== undefined) {
fetchType = bot.exchangeNode.code.API[i].fetchType
if (bot.exchangeNode.config.API[i].fetchType !== undefined) {
fetchType = bot.exchangeNode.config.API[i].fetchType
}
}
}
}
if (bot.code.fetchLimit !== undefined) {
limit = bot.code.fetchLimit
if (bot.config.fetchLimit !== undefined) {
limit = bot.config.fetchLimit
}
let key = process.env.KEY
@@ -151,7 +151,7 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
try {
let reportKey;
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs" + "-" + "dataSet.V1";
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
if (statusDependencies.statusReports.get(reportKey).status === "Status Report is corrupt.") {
@@ -52,25 +52,25 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
exchangeId = bot.exchange.toLowerCase()
/* Applying the parameters defined by the user at the Exchange node */
if (bot.exchangeNode.code.API !== undefined) {
for (let i = 0; i < bot.exchangeNode.code.API.length; i++) {
if (bot.exchangeNode.code.API[i].method === 'fetchTrades') {
if (bot.exchangeNode.code.API[i].class !== undefined) {
exchangeId = bot.exchangeNode.code.API[i].class
if (bot.exchangeNode.config.API !== undefined) {
for (let i = 0; i < bot.exchangeNode.config.API.length; i++) {
if (bot.exchangeNode.config.API[i].method === 'fetchTrades') {
if (bot.exchangeNode.config.API[i].class !== undefined) {
exchangeId = bot.exchangeNode.config.API[i].class
}
if (bot.exchangeNode.code.API[i].fetchType !== undefined) {
fetchType = bot.exchangeNode.code.API[i].fetchType
if (bot.exchangeNode.config.API[i].fetchType !== undefined) {
fetchType = bot.exchangeNode.config.API[i].fetchType
}
if (bot.exchangeNode.code.API[i].fetchTradesMethod !== undefined) {
if (bot.exchangeNode.config.API[i].fetchTradesMethod !== undefined) {
options = {
'fetchTradesMethod': bot.exchangeNode.code.API[i].fetchTradesMethod
'fetchTradesMethod': bot.exchangeNode.config.API[i].fetchTradesMethod
}
}
if (bot.exchangeNode.code.API[i].firstId !== undefined) {
firstId = bot.exchangeNode.code.API[i].firstId
if (bot.exchangeNode.config.API[i].firstId !== undefined) {
firstId = bot.exchangeNode.config.API[i].firstId
}
if (bot.exchangeNode.code.API[i].rateLimit !== undefined) {
rateLimit = bot.exchangeNode.code.API[i].rateLimit
if (bot.exchangeNode.config.API[i].rateLimit !== undefined) {
rateLimit = bot.exchangeNode.config.API[i].rateLimit
}
}
}
@@ -136,7 +136,7 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
try {
let reportKey;
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-Trades" + "-" + "dataSet.V1";
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-Trades"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
if (statusDependencies.statusReports.get(reportKey).status === "Status Report is corrupt.") {
@@ -2,14 +2,8 @@
"displayName": "Exchange Raw Data",
"codeName": "Exchange-Raw-Data",
"type": "Sensor Bot",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"dataMine": "Masters",
"profilePicture": "Exchange Raw Data.png",
"dataSetVersion": "dataSet.V1",
"processes": [
{
"name": "Live-Trades",
@@ -42,12 +36,7 @@
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Live-Trades",
"dataSetVersion": "dataSet.V1"
"process": "Live-Trades"
}
]
},
@@ -82,22 +71,12 @@
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Live-Trades",
"dataSetVersion": "dataSet.V1"
"process": "Live-Trades"
},
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Historic-Trades",
"dataSetVersion": "dataSet.V1"
"process": "Historic-Trades"
}
]
},
@@ -132,44 +111,24 @@
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Live-Trades",
"dataSetVersion": "dataSet.V1",
"waitUntilNextUpdate": true
},
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Historic-Trades",
"dataSetVersion": "dataSet.V1"
"process": "Historic-Trades"
},
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Hole-Fixing",
"dataSetVersion": "dataSet.V1",
"dataSetSection": "Month"
},
{
"dataMine": "Masters",
"bot": "Exchange-Raw-Data",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Hole-Fixing",
"dataSetVersion": "dataSet.V1"
"process": "Hole-Fixing"
}
]
}
@@ -50,7 +50,7 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
try {
let reportKey;
reportKey = "Masters" + "-" + "Webhooks" + "-" + "Check-Webhook" + "-" + "dataSet.V1";
reportKey = "Masters" + "-" + "Webhooks" + "-" + "Check-Webhook"
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
@@ -8,7 +8,6 @@
"patch": 0
},
"dataMine": "Masters",
"dataSetVersion": "dataSet.V1",
"processes": [
{
"name": "Check-Webhook",
@@ -41,12 +40,7 @@
{
"dataMine": "Masters",
"bot": "Webhooks",
"botVersion": {
"major": 1,
"minor": 0
},
"process": "Check-Webhook",
"dataSetVersion": "dataSet.V1"
"process": "Check-Webhook"
}
]
}
@@ -25,7 +25,7 @@
// Secondary functions and properties.
currentRecord: undefined
record: undefined
};
/* this is part of the module template */
@@ -374,13 +374,12 @@
record.begin = dailyFile[1][i][0];
record.end = dailyFile[1][i][1];
record.strategyNumber = dailyFile[1][i][2];
record.strategyPhase = dailyFile[1][i][3];
record.stopLossPhase = dailyFile[1][i][4];
record.takeProfitPhase = dailyFile[1][i][5];
record.conditions = dailyFile[1][i][6];
record.formulaErrors = dailyFile[1][i][7];
record.formulaValues = dailyFile[1][i][8];
record.strategyIndex = dailyFile[1][i][2];
record.variable_current_position_stopLoss_phase = dailyFile[1][i][3];
record.variable_current_position_takeProfit_phase = dailyFile[1][i][4];
record.conditions = dailyFile[1][i][5];
record.formulaErrors = dailyFile[1][i][6];
record.formulaValues = dailyFile[1][i][7];
if (
(record.begin >= farLeftDate.valueOf() && record.end <= farRightDate.valueOf()) &&
@@ -391,8 +390,8 @@
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Condition Changed", thisObject.currentRecord);
thisObject.record = record;
thisObject.container.eventHandler.raiseEvent("Current Condition Changed", thisObject.record);
}
}
@@ -446,13 +445,12 @@
record.begin = marketFile[1][i][0];
record.end = marketFile[1][i][1];
record.strategyNumber = marketFile[1][i][2];
record.strategyPhase = marketFile[1][i][3];
record.stopLossPhase = marketFile[1][i][4];
record.takeProfitPhase = marketFile[1][i][5];
record.conditions = marketFile[1][i][6];
record.formulaErrors = marketFile[1][i][7];
record.formulaValues = marketFile[1][i][8];
record.strategyIndex = marketFile[1][i][2];
record.variable_current_position_stopLoss_phase = marketFile[1][i][3];
record.variable_current_position_takeProfit_phase = marketFile[1][i][4];
record.conditions = marketFile[1][i][5];
record.formulaErrors = marketFile[1][i][6];
record.formulaValues = marketFile[1][i][7];
if (
(record.begin >= leftDate.valueOf() && record.end <= rightDate.valueOf()) &&
@@ -463,8 +461,8 @@
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Condition Changed", thisObject.currentRecord);
thisObject.record = record;
thisObject.container.eventHandler.raiseEvent("Current Condition Changed", thisObject.record);
}
}
@@ -494,18 +492,17 @@
if (userPositionDate >= conditionRecord.begin && userPositionDate <= conditionRecord.end) {
let currentRecord = {
let record = {
conditionsNames: headers,
strategyNumber: conditionRecord.strategyNumber,
strategyPhase: conditionRecord.strategyPhase,
stopLossPhase: conditionRecord.stopLossPhase,
takeProfitPhase: conditionRecord.takeProfitPhase,
strategyIndex: conditionRecord.strategyIndex,
variable_current_position_stopLoss_phase: conditionRecord.variable_current_position_stopLoss_phase,
variable_current_position_takeProfit_phase: conditionRecord.variable_current_position_takeProfit_phase,
conditionsValues: conditionRecord.conditions,
formulaErrors: conditionRecord.formulaErrors,
formulaValues: conditionRecord.formulaValues
};
sendRecordInfoToDesignerSpace(currentRecord)
sendRecordInfoToDesignerSpace(record)
}
}
@@ -515,15 +512,15 @@
}
}
function sendRecordInfoToDesignerSpace(currentRecord) {
function sendRecordInfoToDesignerSpace(record) {
if (currentRecord === undefined) { return; }
if (currentRecord.conditionsNames === undefined) { return; }
if (record === undefined) { return; }
if (record.conditionsNames === undefined) { return; }
if (canvas.designSpace.workspace === undefined) { return; }
/* We will get now the designer trading system */
let designerTradingSystem
let fileTradingSystem = currentRecord.conditionsNames;
let fileTradingSystem = record.conditionsNames;
for (let i = 0; i < canvas.designSpace.workspace.workspaceNode.rootNodes.length; i++) {
let rootNode = canvas.designSpace.workspace.workspaceNode.rootNodes[i]
@@ -568,7 +565,7 @@
let strategy = fileTradingSystem.strategies[j];
designerTradingSystem.strategies[j].payload.uiObject.setErrorMessage(strategy.error)
if (currentRecord.strategyNumber === j) {
if (record.strategyIndex === j) {
designerTradingSystem.strategies[j].payload.uiObject.isExecuting = true
} else {
designerTradingSystem.strategies[j].payload.uiObject.isExecuting = false
@@ -653,7 +650,7 @@
for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) {
if (currentRecord.strategyNumber === j && currentRecord.stopLossPhase === p) {
if (record.strategyIndex === j && record.variable_current_position_stopLoss_phase === p) {
designerTradingSystem.strategies[j].openStage.initialDefinition.stopLoss.phases[p].payload.uiObject.isExecuting = true
} else {
designerTradingSystem.strategies[j].openStage.initialDefinition.stopLoss.phases[p].payload.uiObject.isExecuting = false
@@ -665,15 +662,15 @@
if (phase.formula !== undefined) {
designerTradingSystem.strategies[j].openStage.initialDefinition.stopLoss.phases[p].formula.payload.uiObject.setErrorMessage(openStage.initialDefinition.stopLoss.phases[p].formula.error)
if (currentRecord.formulaErrors[formulaErrorsIndex] !== "") {
if (currentRecord.strategyNumber === j && currentRecord.stopLossPhase === p) {
designerTradingSystem.strategies[j].openStage.initialDefinition.stopLoss.phases[p].formula.payload.uiObject.setErrorMessage(currentRecord.formulaErrors[formulaErrorsIndex])
if (record.formulaErrors[formulaErrorsIndex] !== "") {
if (record.strategyIndex === j && record.variable_current_position_stopLoss_phase === p) {
designerTradingSystem.strategies[j].openStage.initialDefinition.stopLoss.phases[p].formula.payload.uiObject.setErrorMessage(record.formulaErrors[formulaErrorsIndex])
}
}
formulaErrorsIndex++
if (currentRecord.strategyNumber === j && currentRecord.stopLossPhase === p) {
designerTradingSystem.strategies[j].openStage.initialDefinition.stopLoss.phases[p].formula.payload.uiObject.setValue(currentRecord.formulaValues[formulaValuesIndex])
if (record.strategyIndex === j && record.variable_current_position_stopLoss_phase === p) {
designerTradingSystem.strategies[j].openStage.initialDefinition.stopLoss.phases[p].formula.payload.uiObject.setValue(record.formulaValues[formulaValuesIndex])
}
formulaValuesIndex++
}
@@ -738,7 +735,7 @@
for (let p = 0; p < initialDefinition.takeProfit.phases.length; p++) {
if (currentRecord.strategyNumber === j && currentRecord.takeProfitPhase === p) {
if (record.strategyIndex === j && record.variable_current_position_takeProfit_phase === p) {
designerTradingSystem.strategies[j].openStage.initialDefinition.takeProfit.phases[p].payload.uiObject.isExecuting = true
} else {
designerTradingSystem.strategies[j].openStage.initialDefinition.takeProfit.phases[p].payload.uiObject.isExecuting = false
@@ -750,15 +747,15 @@
if (phase.formula !== undefined) {
designerTradingSystem.strategies[j].openStage.initialDefinition.takeProfit.phases[p].formula.payload.uiObject.setErrorMessage(openStage.initialDefinition.takeProfit.phases[p].formula.error)
if (currentRecord.formulaErrors[formulaErrorsIndex] !== "") {
if (currentRecord.strategyNumber === j && currentRecord.takeProfitPhase === p) {
designerTradingSystem.strategies[j].openStage.initialDefinition.takeProfit.phases[p].formula.payload.uiObject.setErrorMessage(currentRecord.formulaErrors[formulaErrorsIndex])
if (record.formulaErrors[formulaErrorsIndex] !== "") {
if (record.strategyIndex === j && record.variable_current_position_takeProfit_phase === p) {
designerTradingSystem.strategies[j].openStage.initialDefinition.takeProfit.phases[p].formula.payload.uiObject.setErrorMessage(record.formulaErrors[formulaErrorsIndex])
}
}
formulaErrorsIndex++
if (currentRecord.strategyNumber === j && currentRecord.takeProfitPhase === p) {
designerTradingSystem.strategies[j].openStage.initialDefinition.takeProfit.phases[p].formula.payload.uiObject.setValue(currentRecord.formulaValues[formulaValuesIndex])
if (record.strategyIndex === j && record.variable_current_position_takeProfit_phase === p) {
designerTradingSystem.strategies[j].openStage.initialDefinition.takeProfit.phases[p].formula.payload.uiObject.setValue(record.formulaValues[formulaValuesIndex])
}
formulaValuesIndex++
}
@@ -836,7 +833,7 @@
for (let p = 0; p < manageStage.stopLoss.phases.length; p++) {
if (currentRecord.strategyNumber === j && currentRecord.stopLossPhase - 1 === p) {
if (record.strategyIndex === j && record.variable_current_position_stopLoss_phase - 1 === p) {
designerTradingSystem.strategies[j].manageStage.stopLoss.phases[p].payload.uiObject.isExecuting = true
} else {
designerTradingSystem.strategies[j].manageStage.stopLoss.phases[p].payload.uiObject.isExecuting = false
@@ -848,14 +845,14 @@
if (phase.formula !== undefined) {
designerTradingSystem.strategies[j].manageStage.stopLoss.phases[p].formula.payload.uiObject.setErrorMessage(manageStage.stopLoss.phases[p].formula.error)
if (currentRecord.formulaErrors[formulaErrorsIndex] !== "") {
if (currentRecord.strategyNumber === j && currentRecord.stopLossPhase - 1 === p) {
designerTradingSystem.strategies[j].manageStage.stopLoss.phases[p].formula.payload.uiObject.setErrorMessage(currentRecord.formulaErrors[formulaErrorsIndex])
if (record.formulaErrors[formulaErrorsIndex] !== "") {
if (record.strategyIndex === j && record.variable_current_position_stopLoss_phase - 1 === p) {
designerTradingSystem.strategies[j].manageStage.stopLoss.phases[p].formula.payload.uiObject.setErrorMessage(record.formulaErrors[formulaErrorsIndex])
}
}
formulaErrorsIndex++
if (currentRecord.strategyNumber === j && currentRecord.stopLossPhase - 1 === p) {
designerTradingSystem.strategies[j].manageStage.stopLoss.phases[p].formula.payload.uiObject.setValue(currentRecord.formulaValues[formulaValuesIndex])
if (record.strategyIndex === j && record.variable_current_position_stopLoss_phase - 1 === p) {
designerTradingSystem.strategies[j].manageStage.stopLoss.phases[p].formula.payload.uiObject.setValue(record.formulaValues[formulaValuesIndex])
}
formulaValuesIndex++
}
@@ -920,7 +917,7 @@
for (let p = 0; p < manageStage.takeProfit.phases.length; p++) {
if (currentRecord.strategyNumber === j && currentRecord.takeProfitPhase - 1 === p) {
if (record.strategyIndex === j && record.variable_current_position_takeProfit_phase - 1 === p) {
designerTradingSystem.strategies[j].manageStage.takeProfit.phases[p].payload.uiObject.isExecuting = true
} else {
designerTradingSystem.strategies[j].manageStage.takeProfit.phases[p].payload.uiObject.isExecuting = false
@@ -932,15 +929,15 @@
if (phase.formula !== undefined) {
designerTradingSystem.strategies[j].manageStage.takeProfit.phases[p].formula.payload.uiObject.setErrorMessage(manageStage.takeProfit.phases[p].formula.error)
if (currentRecord.formulaErrors[formulaErrorsIndex] !== "") {
if (currentRecord.strategyNumber === j && currentRecord.takeProfitPhase - 1 === p) {
designerTradingSystem.strategies[j].manageStage.takeProfit.phases[p].formula.payload.uiObject.setErrorMessage(currentRecord.formulaErrors[formulaErrorsIndex])
if (record.formulaErrors[formulaErrorsIndex] !== "") {
if (record.strategyIndex === j && record.variable_current_position_takeProfit_phase - 1 === p) {
designerTradingSystem.strategies[j].manageStage.takeProfit.phases[p].formula.payload.uiObject.setErrorMessage(record.formulaErrors[formulaErrorsIndex])
}
}
formulaErrorsIndex++
if (currentRecord.strategyNumber === j && currentRecord.takeProfitPhase - 1 === p) {
designerTradingSystem.strategies[j].manageStage.takeProfit.phases[p].formula.payload.uiObject.setValue(currentRecord.formulaValues[formulaValuesIndex])
if (record.strategyIndex === j && record.variable_current_position_takeProfit_phase - 1 === p) {
designerTradingSystem.strategies[j].manageStage.takeProfit.phases[p].formula.payload.uiObject.setValue(record.formulaValues[formulaValuesIndex])
}
formulaValuesIndex++
}
@@ -1032,7 +1029,7 @@
}
}
if (currentRecord.conditionsValues[conditionIndex] === 1) {
if (record.conditionsValues[conditionIndex] === 1) {
condition.payload.uiObject.highlight()
} else {
highlightSituation = false
@@ -1,348 +0,0 @@
function newAAMastersPlottersTradingSimulationFinalResults() {
const MODULE_NAME = "Final Results Plotter";
const ERROR_LOG = true;
const INTENSIVE_LOG = false;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let thisObject = {
// Main functions and properties.
initialize: initialize,
finalize: finalize,
container: undefined,
getContainer: getContainer,
setTimePeriod: setTimePeriod,
setDatetime: setDatetime,
draw: draw,
recalculateScale: recalculateScale,
currentRecord: undefined
};
/* this is part of the module template */
let container = newContainer(); // Do not touch this 3 lines, they are just needed.
container.initialize();
thisObject.container = container;
let timeLineCoordinateSystem = newTimeLineCoordinateSystem(); // Needed to be able to plot on the timeline, otherwise not.
let timePeriod; // This will hold the current Time Period the user is at.
let datetime; // This will hold the current Datetime the user is at.
let dataFile; // This is the current Market File being plotted.
let fileCursor; // This is the current File Cursor being used to retrieve Daily Files.
let singleFile; // This object will provide the different Market Files at different Time Periods.
/* these are module specific variables: */
let records = []; // Here we keep the records to be ploted every time the Draw() function is called by the AAWebPlatform.
let imageStopLossPhase;
let imageTakeProfitPhase;
let imageRecord;
let zoomChangedEventSubscriptionId
let offsetChangedEventSubscriptionId
let filesUpdatedEventSubscriptionId
let dragFinishedEventSubscriptionId
let dimmensionsChangedEventSubscriptionId
return thisObject;
function finalize() {
try {
/* Stop listening to the necesary events. */
viewPort.eventHandler.stopListening(zoomChangedEventSubscriptionId);
viewPort.eventHandler.stopListening(offsetChangedEventSubscriptionId);
singleFile.eventHandler.stopListening(filesUpdatedEventSubscriptionId);
canvas.eventHandler.stopListening(dragFinishedEventSubscriptionId);
thisObject.container.eventHandler.stopListening(dimmensionsChangedEventSubscriptionId)
/* icons */
imageStopLossPhase = undefined;
imageTakeProfitPhase = undefined;
imageRecord = undefined;
/* Destroy References */
singleFile = undefined;
datetime = undefined;
timePeriod = undefined;
dataFile = undefined;
fileCursor = undefined;
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] finalize -> err = " + err.stack); }
}
}
function initialize(pStorage, pExchange, pMarket, pDatetime, pTimePeriod, callBackFunction) {
try {
/* Store the information received. */
singleFile = pStorage.singleFile;
datetime = pDatetime;
timePeriod = pTimePeriod;
dataFile = singleFile.getFile(timePeriod);
/* Listen to the necesary events. */
zoomChangedEventSubscriptionId = viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged);
offsetChangedEventSubscriptionId = viewPort.eventHandler.listenToEvent("Offset Changed", onOffsetChanged);
filesUpdatedEventSubscriptionId = singleFile.eventHandler.listenToEvent("Files Updated", onFilesUpdated);
dragFinishedEventSubscriptionId = canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished);
/* Get ready for plotting. */
recalculate();
/* Ready for when dimmension changes. */
dimmensionsChangedEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('Dimmensions Changed', function () {
recalculate();
})
callBackFunction();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err.stack); }
}
}
function getContainer(point) {
let container;
/* First we check if this point is inside this space. */
if (this.container.frame.isThisPointHere(point) === true) {
return this.container;
} else {
/* This point does not belong to this space. */
return undefined;
}
}
function onFilesUpdated() {
try {
dataFile = singleFile.getFile(timePeriod);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onFilesUpdated -> err = " + err.stack); }
}
}
function setTimePeriod(pTimePeriod) {
try {
if (timePeriod !== pTimePeriod) {
timePeriod = pTimePeriod;
dataFile = singleFile.getFile(timePeriod);
recalculate();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] setTimePeriod -> err = " + err.stack); }
}
}
function setDatetime(pDatetime) {
datetime = pDatetime;
}
function draw() {
try {
// Nothing to draw for now
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] draw -> err = " + err.stack); }
}
}
function recalculate() {
try {
records = []
if (timePeriod >= _1_HOUR_IN_MILISECONDS) {
recalculateUsingMarketFiles();
} else {
recalculateUsingDailyFiles();
}
thisObject.container.eventHandler.raiseEvent("Records Changed", records);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] recalculate -> err = " + err.stack); }
}
}
function recalculate() {
try {
if (dataFile === undefined) { return; } // Initialization not complete yet.
records = [];
for (let i = 0; i < dataFile.length; i++) {
let record = {};
record.begin = dataFile[i][0];
record.end = dataFile[i][1];
record.type = dataFile[i][2];
record.rate = dataFile[i][3];
record.amount = dataFile[i][4];
record.balanceA = dataFile[i][5];
record.balanceB = dataFile[i][6];
record.profit = dataFile[i][7];
record.lastTradeProfitLoss = dataFile[i][8];
record.stopLoss = dataFile[i][9];
record.roundtrips = dataFile[i][10];
record.hits = dataFile[i][11];
record.fails = dataFile[i][12];
record.hitRatio = dataFile[i][13];
record.ROI = dataFile[i][14];
record.periods = dataFile[i][15];
record.days = dataFile[i][16];
record.anualizedRateOfReturn = dataFile[i][17];
record.sellRate = dataFile[i][18];
record.lastTradeROI = dataFile[i][19];
record.strategy = dataFile[i][20];
record.strategyPhase = dataFile[i][21];
record.takeProfit = dataFile[i][22];
record.stopLossPhase = dataFile[i][23];
record.takeProfitPhase = dataFile[i][24];
record.positionSize = dataFile[i][26]; // 25 is the message for the executor
record.initialBalanceA = dataFile[i][27];
record.minimunBalanceA = dataFile[i][28];
record.maximunBalanceA = dataFile[i][29];
record.initialBalanceB = dataFile[i][30];
record.minimunBalanceB = dataFile[i][31];
record.maximunBalanceB = dataFile[i][32];
record.baseAsset = dataFile[i][33];
record.positionPeriods = dataFile[i][34];
record.positionDays = dataFile[i][35];
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.currentRecord);
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] recalculate -> err = " + err.stack); }
}
}
function recalculateScale() {
try {
// No scale needed
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateScale -> err = " + err.stack); }
}
}
function plotChart() {
try {
let userPosition = getUserPosition()
let userPositionDate = userPosition.point.x
let record;
/* Now we calculate and plot the records */
for (let i = 0; i < records.length; i++) { // We do not start in 0 so as to be able to read the previous record i - 1
record = records[i];
/* Send the current record to the panel */
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
let eventRecords = {
currentRecord: record,
lastRecord: records[records.length - 1]
};
thisObject.container.eventHandler.raiseEvent("Current Record Changed", eventRecords);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] plotChart -> err = " + err.stack); }
}
}
function onZoomChanged(event) {
try {
recalculate();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onZoomChanged -> err = " + err.stack); }
}
}
function onOffsetChanged() {
try {
if (Math.random() * 100 > 95) {
recalculate()
};
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onOffsetChanged -> err = " + err.stack); }
}
}
function onDragFinished() {
try {
recalculate();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onDragFinished -> err = " + err.stack); }
}
}
}
@@ -1,360 +0,0 @@

function newAAMastersPlottersTradingSimulationTradingSimulationFinalResultsPanel() {
let thisObject = {
fitFunction: undefined,
onEventRaised: onEventRaised,
container: undefined,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
};
let container = newContainer();
container.initialize();
thisObject.container = container;
container.displacement.containerName = "Final Results";
container.frame.containerName = "Final Results";
let currentRecord;
let lastRecord;
let panelTabButton
return thisObject;
function initialize() {
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL * 2;
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL * 2.5;
thisObject.container.frame.position.x = viewPort.visibleArea.topLeft.x + thisObject.container.frame.width * 1;
thisObject.container.frame.position.y = viewPort.visibleArea.topRight.y;
panelTabButton = newPanelTabButton()
panelTabButton.parentContainer = thisObject.container
panelTabButton.container.frame.parentFrame = thisObject.container.frame
panelTabButton.fitFunction = thisObject.fitFunction
panelTabButton.initialize()
}
function finalize() {
}
function getContainer(point) {
let container;
container = panelTabButton.getContainer(point)
if (container !== undefined) { return container }
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
let checkPoint = {
x: point.x,
y: point.y
}
checkPoint = thisObject.fitFunction(checkPoint)
if (point.x === checkPoint.x && point.y === checkPoint.y) {
return thisObject.container;
}
}
}
function onEventRaised(records) {
currentRecord = records.currentRecord;
lastRecord = records.lastRecord
}
function draw() {
thisObject.container.frame.draw(false, false, true, thisObject.fitFunction);
plotCurrentRecordInfo();
panelTabButton.draw()
}
function plotCurrentRecordInfo() {
if (currentRecord === undefined) { return; }
if (lastRecord === undefined) { return; }
const frameBodyHeight = thisObject.container.frame.getBodyHeight();
const frameTitleHeight = thisObject.container.frame.height - frameBodyHeight;
const X_AXIS = thisObject.container.frame.width / 2;
const Y_AXIS = frameTitleHeight + frameBodyHeight / 2;
/* put the labels with the records values */
browserCanvasContext.beginPath();
let y = 0;
let increment = 0.024;
y = y + increment;
y = y + increment;
printLabel('Current Position', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1', 14);
y = y + increment;
printLabel('Size', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(currentRecord.positionSize, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Rate', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(currentRecord.sellRate, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Stop', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(currentRecord.stopLoss, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Take Profit', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(currentRecord.takeProfit, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Periods', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel((currentRecord.positionPeriods), X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Days', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel((currentRecord.positionDays).toFixed(2), X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
y = y + increment;
printLabel('Latest Position', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1', 14);
y = y + increment;
printLabel('Profit / Loss', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel((currentRecord.lastTradeProfitLoss), X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('ROI', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel((currentRecord.lastTradeROI).toFixed(2) + ' % ', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
let bifurcationLevel = y
y = y + increment;
y = y + increment;
printLabel('Partial Results', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1', 14);
y = y + increment;
printLabel('Profit / Loss', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(currentRecord.profit, X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Trades', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(currentRecord.roundtrips, X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Hits', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(currentRecord.hits, X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Fails', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(currentRecord.fails, X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Hit Ratio', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel((currentRecord.hitRatio * 100).toFixed(2) + ' %', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('ROI', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel((currentRecord.ROI * 100).toFixed(2) + ' %', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Periods', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(currentRecord.periods, X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Days', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(currentRecord.days, X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Anualized Rate of Return', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel((currentRecord.anualizedRateOfReturn * 100).toFixed(2) + ' %', X_AXIS - thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = bifurcationLevel
y = y + increment;
y = y + increment;
printLabel('Final Results', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1', 14);
y = y + increment;
printLabel('Profit / Loss', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(lastRecord.profit, X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Trades', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(lastRecord.roundtrips, X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Hits', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(lastRecord.hits, X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Fails', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(lastRecord.fails, X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Hit Ratio', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel((lastRecord.hitRatio * 100).toFixed(2) + ' %', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('ROI', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel((lastRecord.ROI * 100).toFixed(2) + ' %', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Periods', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(lastRecord.periods, X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Days', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel(lastRecord.days, X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
y = y + increment;
printLabel('Anualized Rate of Return', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '0.60');
y = y + increment;
printLabel((lastRecord.anualizedRateOfReturn * 100).toFixed(2) + ' %', X_AXIS + thisObject.container.frame.width / 4, frameTitleHeight + frameBodyHeight * y, '1.00', 14);
function printLabel(labelToPrint, x, y, opacity, fontSize) {
let labelPoint;
if (fontSize === undefined) { fontSize = 10 };
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY;
let label = '' + labelToPrint;
if (isNaN(label) === false) {
label = Number(label).toLocaleString();
if ((label === "-0" || label === "0") && (labelToPrint !== 0) && (labelToPrint !== "0.00")) {
label = Number(labelToPrint).toFixed(6);
}
}
let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO;
labelPoint = {
x: x - xOffset,
y: y
};
labelPoint = thisObject.container.frame.frameThisPoint(labelPoint);
labelPoint = thisObject.fitFunction(labelPoint)
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', ' + opacity + ')';
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
}
browserCanvasContext.closePath();
browserCanvasContext.fill();
/* Parameters */
let params
let paramsArray = []
let positionTaken = false
if (currentRecord.positionSize > 0) {
positionTaken = true
}
params = {}
params.VALUE = currentRecord.balanceA;
params.INIT_VALUE = currentRecord.initialBalanceA
params.MIN_VALUE = currentRecord.minimunBalanceA
params.MAX_VALUE = currentRecord.maximunBalanceA
params.ASSET_LABEL = 'Asset A'
params.ASSET_NAME = DEFAULT_MARKET.assetB
params.LEFT_OFFSET = 100
params.POSITION_TAKEN = positionTaken
params.BASE_ASSET = currentRecord.baseAsset
params.DECIMALS = 4
paramsArray.push(params)
params = {}
params.VALUE = currentRecord.balanceB;
params.MIN_VALUE = currentRecord.minimunBalanceB
params.INIT_VALUE = currentRecord.initialBalanceB
params.MAX_VALUE = currentRecord.maximunBalanceB
params.ASSET_LABEL = 'Asset B'
params.ASSET_NAME = DEFAULT_MARKET.assetA
params.LEFT_OFFSET = 220
params.POSITION_TAKEN = positionTaken
params.BASE_ASSET = currentRecord.baseAsset
params.DECIMALS = 2
paramsArray.push(params)
canvas.cockpitSpace.assetBalances.setParamsArray(paramsArray)
}
}
@@ -342,7 +342,7 @@
function plotChart() {
try {
let currentRecord
let record
let point = {
x: 0,
@@ -358,7 +358,7 @@
for (let i = 0; i < history.length; i++) {
record = history[i];
currentRecord = record
record = record
let timestamp = record.date // Math.trunc(record.date / timeFrame) * timeFrame + timeFrame / 2;
@@ -427,7 +427,7 @@
point2.y = point2.y - diff;
point3.y = point3.y - diff;
currentRecord.timeFrame = diff
record.timeFrame = diff
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
@@ -502,7 +502,7 @@
point2.y = point2.y + diff;
point3.y = point3.y + diff;
currentRecord.timeFrame = diff
record.timeFrame = diff
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
@@ -575,7 +575,7 @@
point2.y = point2.y - diff;
point3.y = point3.y - diff;
currentRecord.timeFrame = diff
record.timeFrame = diff
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
@@ -649,7 +649,7 @@
point2.y = point2.y + diff;
point3.y = point3.y + diff;
currentRecord.timeFrame = diff
record.timeFrame = diff
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
@@ -683,7 +683,7 @@
/* Send the current record to the panel */
if (userPositionDate >= record.date - 30000 && userPositionDate < record.date + 30000) {
thisObject.container.eventHandler.raiseEvent("Current Record Changed", currentRecord);
thisObject.container.eventHandler.raiseEvent("Current Record Changed", record);
}
/* Circles */
@@ -19,7 +19,7 @@ function newTradingEnginesPlottersTradingSimulationSimulationExecutionSimulation
container.frame.containerName = "Trading Execution";
let currentRecord;
let record;
let upDownButton
return thisObject;
@@ -30,7 +30,7 @@ function newTradingEnginesPlottersTradingSimulationSimulationExecutionSimulation
thisObject.fitFunction = undefined
thisObject.isVisible = undefined
currentRecord = undefined
record = undefined
upDownButton.finalize()
upDownButton = undefined
}
@@ -75,7 +75,7 @@ function newTradingEnginesPlottersTradingSimulationSimulationExecutionSimulation
function onRecordChange(lastCurrentCandle) {
currentRecord = lastCurrentCandle;
record = lastCurrentCandle;
}
@@ -93,7 +93,7 @@ function newTradingEnginesPlottersTradingSimulationSimulationExecutionSimulation
function plot() {
if (currentRecord === undefined) { return; }
if (record === undefined) { return; }
const frameBodyHeight = thisObject.container.frame.getBodyHeight();
const frameTitleHeight = thisObject.container.frame.height - frameBodyHeight;
@@ -101,7 +101,7 @@ function newTradingEnginesPlottersTradingSimulationSimulationExecutionSimulation
const X_AXIS = thisObject.container.frame.width / 2;
const Y_AXIS = frameTitleHeight + frameBodyHeight / 2;
record = currentRecord
record = record
point = {
x: X_AXIS,
@@ -395,28 +395,28 @@ function newTradingEnginesPlottersTradingSimulationSimulationExecutionSimulation
browserCanvasContext.beginPath();
let y;
let recordDate = new Date(currentRecord.datetime)
let recordDate = new Date(record.datetime)
printLabel('Market Rate', X_AXIS, frameTitleHeight + frameBodyHeight * 0.05 / 2, '1');
printLabel(currentRecord.marketRate, X_AXIS, frameTitleHeight + frameBodyHeight * 0.10 / 2, '0.50');
printLabel(record.marketRate, X_AXIS, frameTitleHeight + frameBodyHeight * 0.10 / 2, '0.50');
printLabel('Sell Rate', X_AXIS, frameTitleHeight + frameBodyHeight * 0.15 / 2, '1');
printLabel(currentRecord.lastSellRate, X_AXIS, frameTitleHeight + frameBodyHeight * 0.20 / 2, '0.50');
printLabel(record.lastSellRate, X_AXIS, frameTitleHeight + frameBodyHeight * 0.20 / 2, '0.50');
printLabel('Sell Executed Rate', X_AXIS, frameTitleHeight + frameBodyHeight * 0.25 / 2, '1');
printLabel(currentRecord.sellExecRate, X_AXIS, frameTitleHeight + frameBodyHeight * 0.30 / 2, '0.50');
printLabel(record.sellExecRate, X_AXIS, frameTitleHeight + frameBodyHeight * 0.30 / 2, '0.50');
printLabel('Buy Rate', X_AXIS, frameTitleHeight + frameBodyHeight * 0.35 / 2, '1');
printLabel(currentRecord.lastBuyRate, X_AXIS, frameTitleHeight + frameBodyHeight * 0.40 / 2, '0.40');
printLabel(record.lastBuyRate, X_AXIS, frameTitleHeight + frameBodyHeight * 0.40 / 2, '0.40');
printLabel('Buy Executed Rate', X_AXIS, frameTitleHeight + frameBodyHeight * 0.45 / 2, '1');
printLabel(currentRecord.buyExecRate, X_AXIS, frameTitleHeight + frameBodyHeight * 0.50 / 2, '0.50');
printLabel(record.buyExecRate, X_AXIS, frameTitleHeight + frameBodyHeight * 0.50 / 2, '0.50');
printLabel('ROI Asset A', X_AXIS, frameTitleHeight + frameBodyHeight * (1 - 0.25 / 2), '1');
printLabel((currentRecord.combinedProfitsB).toFixed(2) + '%', X_AXIS, frameTitleHeight + frameBodyHeight * (1 - 0.30 / 2), '0.50');
printLabel((record.combinedProfitsB).toFixed(2) + '%', X_AXIS, frameTitleHeight + frameBodyHeight * (1 - 0.30 / 2), '0.50');
printLabel('ROI Asset B', X_AXIS, frameTitleHeight + frameBodyHeight * (1 - 0.15 / 2), '1');
printLabel((currentRecord.combinedProfitsA).toFixed(2) + '%', X_AXIS, frameTitleHeight + frameBodyHeight * (1 - 0.20 / 2), '0.50');
printLabel((record.combinedProfitsA).toFixed(2) + '%', X_AXIS, frameTitleHeight + frameBodyHeight * (1 - 0.20 / 2), '0.50');
printLabel('Datetime', X_AXIS, frameTitleHeight + frameBodyHeight * (1 - 0.05 / 2), '1');
printLabel(recordDate.toUTCString(), X_AXIS, frameTitleHeight + frameBodyHeight * (1 - 0.1 / 2), '0.50');
@@ -27,7 +27,7 @@
// Secondary functions and properties.
currentRecord: undefined
record: undefined
};
/* this is part of the module template */
@@ -383,7 +383,7 @@
record.number = dailyFile[i][3];
record.beginRate = dailyFile[i][4];
record.endRate = dailyFile[i][5];
record.triggerOnSituation = dailyFile[i][6];
record.situationName = dailyFile[i][6];
record.name = dailyFile[i][7];
if (
@@ -395,8 +395,8 @@
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Strategy Changed", thisObject.currentRecord);
thisObject.record = record;
thisObject.container.eventHandler.raiseEvent("Current Strategy Changed", thisObject.record);
}
}
@@ -456,7 +456,7 @@
record.number = marketFile[i][3];
record.beginRate = marketFile[i][4];
record.endRate = marketFile[i][5];
record.triggerOnSituation = marketFile[i][6];
record.situationName = marketFile[i][6];
record.name = marketFile[i][7];
if (record.begin >= leftDate.valueOf() && record.end <= rightDate.valueOf()) {
@@ -468,8 +468,8 @@
(record.begin >= coordinateSystem.min.x && record.end <= coordinateSystem.max.x)
) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Strategy Changed", thisObject.currentRecord);
thisObject.record = record;
thisObject.container.eventHandler.raiseEvent("Current Strategy Changed", thisObject.record);
}
}
@@ -588,8 +588,8 @@
if (record.name !== "New Strategy") {
printLabel(record.name, recordPoint1.x + 5, positionY - 15, '1', 12);
}
if (record.triggerOnSituation !== "New Situation") {
printLabel(record.triggerOnSituation, recordPoint1.x + 5, positionY, '1', 12);
if (record.situationName !== "New Situation") {
printLabel(record.situationName, recordPoint1.x + 5, positionY, '1', 12);
}
}
@@ -609,9 +609,9 @@
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
let currentRecord = {
let record = {
};
thisObject.container.eventHandler.raiseEvent("Current Strategy Record Changed", currentRecord);
thisObject.container.eventHandler.raiseEvent("Current Strategy Record Changed", record);
}
function drawStick(point1, point2) {
@@ -27,7 +27,7 @@
// Secondary functions and properties.
currentRecord: undefined
record: undefined
};
/* this is part of the module template */
@@ -366,11 +366,11 @@
record.begin = dailyFile[i][0];
record.end = dailyFile[i][1];
record.status = dailyFile[i][2];
record.lastTradeROI = dailyFile[i][3];
record.variable_last_position_ROI = dailyFile[i][3];
record.beginRate = dailyFile[i][4];
record.endRate = dailyFile[i][5];
record.exitType = dailyFile[i][6];
record.takePositionSituation = dailyFile[i][7];
record.situationName = dailyFile[i][7];
if (
(record.begin >= farLeftDate.valueOf() && record.end <= farRightDate.valueOf()) &&
@@ -381,8 +381,8 @@
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Trade Changed", thisObject.currentRecord);
thisObject.record = record;
thisObject.container.eventHandler.raiseEvent("Current Trade Changed", thisObject.record);
}
}
@@ -432,11 +432,11 @@
record.begin = marketFile[i][0];
record.end = marketFile[i][1];
record.status = marketFile[i][2];
record.lastTradeROI = marketFile[i][3];
record.variable_last_position_ROI = marketFile[i][3];
record.beginRate = marketFile[i][4];
record.endRate = marketFile[i][5];
record.exitType = marketFile[i][6];
record.takePositionSituation = marketFile[i][7];
record.situationName = marketFile[i][7];
if (
(record.begin >= leftDate.valueOf() && record.end <= rightDate.valueOf()) &&
@@ -447,8 +447,8 @@
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Trade Changed", thisObject.currentRecord);
thisObject.record = record;
thisObject.container.eventHandler.raiseEvent("Current Trade Changed", thisObject.record);
}
}
@@ -478,9 +478,9 @@
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
let currentRecord = {
let record = {
};
thisObject.container.eventHandler.raiseEvent("Current Trade Record Changed", currentRecord);
thisObject.container.eventHandler.raiseEvent("Current Trade Record Changed", record);
}
let recordPoint1 = {
@@ -518,7 +518,7 @@
recordPoint2 = thisObject.fitFunction(recordPoint2);
recordPoint3 = thisObject.fitFunction(recordPoint3);
let line0 = record.takePositionSituation
let line0 = record.situationName
let line1 = '';
let line2 = '';
@@ -541,10 +541,10 @@
line1 = 'Open Position';
}
if (record.lastTradeROI < 0) {
line2 = 'ROI:' + (record.lastTradeROI).toFixed(2) + ' %';
if (record.variable_last_position_ROI < 0) {
line2 = 'ROI:' + (record.variable_last_position_ROI).toFixed(2) + ' %';
} else {
line2 = 'ROI:' + (record.lastTradeROI).toFixed(2) + ' %';
line2 = 'ROI:' + (record.variable_last_position_ROI).toFixed(2) + ' %';
}
/* Draw the triangle that represents the trade. */
@@ -559,7 +559,7 @@
let opacity = '0.25';
if (record.lastTradeROI > 0) {
if (record.variable_last_position_ROI > 0) {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + opacity + ')';
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + opacity + ')';
} else {
@@ -26,7 +26,7 @@
// Secondary functions and properties.
currentRecord: undefined
record: undefined
};
/* this is part of the module template */
@@ -149,7 +149,7 @@
/* Loading a few icons */
imageStopLossPhase = canvas.designSpace.iconByUiObjectType.get('Stop');
imageStopLossPhase = canvas.designSpace.iconByUiObjectType.get('Managed Stop Loss');
imageTakeProfitPhase = canvas.designSpace.iconByUiObjectType.get('Phase');
imageRecord = canvas.designSpace.iconByUiObjectType.get('Trading System');
@@ -353,42 +353,38 @@
record.begin = dailyFile[i][0];
record.end = dailyFile[i][1];
record.type = dailyFile[i][2];
record.rate = dailyFile[i][3];
record.amount = dailyFile[i][4];
record.balanceA = dailyFile[i][5];
record.balanceB = dailyFile[i][6];
record.profit = dailyFile[i][7];
record.lastTradeProfitLoss = dailyFile[i][8];
record.stopLoss = dailyFile[i][9];
record.roundtrips = dailyFile[i][10];
record.hits = dailyFile[i][11];
record.fails = dailyFile[i][12];
record.hitRatio = dailyFile[i][13];
record.ROI = dailyFile[i][14];
record.periods = dailyFile[i][15];
record.days = dailyFile[i][16];
record.anualizedRateOfReturn = dailyFile[i][17];
record.sellRate = dailyFile[i][18];
record.lastTradeROI = dailyFile[i][19];
record.strategy = dailyFile[i][20];
record.strategyPhase = dailyFile[i][21];
record.takeProfit = dailyFile[i][22];
record.stopLossPhase = dailyFile[i][23];
record.takeProfitPhase = dailyFile[i][24];
record.positionSize = dailyFile[i][26]; // 25 is the message for the executor
record.initialBalanceA = dailyFile[i][27];
record.minimunBalanceA = dailyFile[i][28];
record.maximunBalanceA = dailyFile[i][29];
record.initialBalanceB = dailyFile[i][30];
record.minimunBalanceB = dailyFile[i][31];
record.maximunBalanceB = dailyFile[i][32];
record.baseAsset = dailyFile[i][33];
record.quotedAsset = dailyFile[i][34];
record.marketBaseAsset = dailyFile[i][35];
record.marketQuotedAsset = dailyFile[i][36];
record.positionPeriods = dailyFile[i][37];
record.positionDays = dailyFile[i][38];
record.variable_current_balance_baseAsset = dailyFile[i][2];
record.variable_current_balance_quotedAsset = dailyFile[i][3];
record.variable_episode_stat_profitLoss = dailyFile[i][4];
record.variable_last_position_profitLoss = dailyFile[i][5];
record.variable_current_position_stopLoss_value = dailyFile[i][6];
record.variable_episode_count_positions = dailyFile[i][7];
record.variable_episode_count_hits = dailyFile[i][8];
record.variable_episode_count_fails = dailyFile[i][9];
record.variable_episode_stat_hitRatio = dailyFile[i][10];
record.variable_episode_stat_ROI = dailyFile[i][11];
record.variable_episode_count_periods = dailyFile[i][12];
record.variable_episode_stat_days = dailyFile[i][13];
record.variable_episode_stat_anualizedRateOfReturn = dailyFile[i][14];
record.variable_current_position_rate = dailyFile[i][15];
record.variable_last_position_ROI = dailyFile[i][16];
record.strategy = dailyFile[i][17];
record.variable_current_position_takeProfit_value = dailyFile[i][18];
record.variable_current_position_stopLoss_phase = dailyFile[i][19];
record.variable_current_position_takeProfit_phase = dailyFile[i][20];
record.variable_current_position_size = dailyFile[i][21]; // 25 is the message for the executor
record.variable_episode_parameters_initial_balance_baseAsset = dailyFile[i][22];
record.variable_episode_parameters_minimum_balance_baseAsset = dailyFile[i][23];
record.variable_episode_parameters_maximum_balance_baseAsset = dailyFile[i][24];
record.variable_episode_parameters_initial_balance_quotedAsset = dailyFile[i][25];
record.variable_episode_parameters_minimum_balance_quotedAsset = dailyFile[i][26];
record.variable_episode_parameters_maximum_balance_quotedAsset = dailyFile[i][27];
record.variable_episode_parameters_baseAsset = dailyFile[i][28];
record.variable_episode_parameters_quotedAsset = dailyFile[i][29];
record.variable_episode_parameters_marketBaseAsset = dailyFile[i][30];
record.variable_episode_parameters_marketQuotedAsset = dailyFile[i][31];
record.variable_current_position_count_periods = dailyFile[i][32];
record.variable_current_position_stat_days = dailyFile[i][33];
if (
(record.begin >= farLeftDate.valueOf() && record.end <= farRightDate.valueOf()) &&
@@ -399,8 +395,8 @@
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.currentRecord);
thisObject.record = record;
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.record);
}
}
@@ -447,42 +443,37 @@
record.begin = marketFile[i][0];
record.end = marketFile[i][1];
record.type = marketFile[i][2];
record.rate = marketFile[i][3];
record.amount = marketFile[i][4];
record.balanceA = marketFile[i][5];
record.balanceB = marketFile[i][6];
record.profit = marketFile[i][7];
record.lastTradeProfitLoss = marketFile[i][8];
record.stopLoss = marketFile[i][9];
record.roundtrips = marketFile[i][10];
record.hits = marketFile[i][11];
record.fails = marketFile[i][12];
record.hitRatio = marketFile[i][13];
record.ROI = marketFile[i][14];
record.periods = marketFile[i][15];
record.days = marketFile[i][16];
record.anualizedRateOfReturn = marketFile[i][17];
record.sellRate = marketFile[i][18];
record.lastTradeROI = marketFile[i][19];
record.strategy = marketFile[i][20];
record.strategyPhase = marketFile[i][21];
record.takeProfit = marketFile[i][22];
record.stopLossPhase = marketFile[i][23];
record.takeProfitPhase = marketFile[i][24];
record.positionSize = marketFile[i][26]; // 25 is the message for the executor
record.initialBalanceA = marketFile[i][27];
record.minimunBalanceA = marketFile[i][28];
record.maximunBalanceA = marketFile[i][29];
record.initialBalanceB = marketFile[i][30];
record.minimunBalanceB = marketFile[i][31];
record.maximunBalanceB = marketFile[i][32];
record.baseAsset = marketFile[i][33];
record.quotedAsset = marketFile[i][34];
record.marketBaseAsset = marketFile[i][35];
record.marketQuotedAsset = marketFile[i][36];
record.positionPeriods = marketFile[i][37];
record.positionDays = marketFile[i][38];
record.variable_current_balance_baseAsset = marketFile[i][2];
record.variable_current_balance_quotedAsset = marketFile[i][3];
record.variable_episode_stat_profitLoss = marketFile[i][4];
record.variable_last_position_profitLoss = marketFile[i][5];
record.variable_current_position_stopLoss_value = marketFile[i][6];
record.variable_episode_count_positions = marketFile[i][7];
record.variable_episode_count_hits = marketFile[i][8];
record.variable_episode_count_fails = marketFile[i][9];
record.variable_episode_stat_hitRatio = marketFile[i][10];
record.variable_episode_stat_ROI = marketFile[i][11];
record.variable_episode_count_periods = marketFile[i][12];
record.variable_episode_stat_days = marketFile[i][13];
record.variable_episode_stat_anualizedRateOfReturn = marketFile[i][14];
record.variable_current_position_rate = marketFile[i][15];
record.variable_last_position_ROI = marketFile[i][16];
record.variable_current_position_takeProfit_value = marketFile[i][17];
record.variable_current_position_stopLoss_phase = marketFile[i][18];
record.variable_current_position_takeProfit_phase = marketFile[i][19];
record.variable_current_position_size = marketFile[i][20];
record.variable_episode_parameters_initial_balance_baseAsset = marketFile[i][21];
record.variable_episode_parameters_minimum_balance_baseAsset = marketFile[i][22];
record.variable_episode_parameters_maximum_balance_baseAsset = marketFile[i][23];
record.variable_episode_parameters_initial_balance_quotedAsset = marketFile[i][24];
record.variable_episode_parameters_minimum_balance_quotedAsset = marketFile[i][25];
record.variable_episode_parameters_maximum_balance_quotedAsset = marketFile[i][26];
record.variable_episode_parameters_baseAsset = marketFile[i][27];
record.variable_episode_parameters_quotedAsset = marketFile[i][28];
record.variable_episode_parameters_marketBaseAsset = marketFile[i][29];
record.variable_episode_parameters_marketQuotedAsset = marketFile[i][30];
record.variable_current_position_count_periods = marketFile[i][31];
record.variable_current_position_stat_days = marketFile[i][32];
if (
(record.begin >= leftDate.valueOf() && record.end <= rightDate.valueOf()) &&
@@ -493,8 +484,8 @@
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.currentRecord);
thisObject.record = record;
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.record);
}
}
@@ -521,11 +512,11 @@
record = records[i];
/* Contributing to Auto-Scale*/
if (record.stopLoss !== 0) {
coordinateSystem.reportYValue(record.stopLoss)
if (record.variable_current_position_stopLoss_value !== 0) {
coordinateSystem.reportYValue(record.variable_current_position_stopLoss_value)
}
if (record.takeProfit !== 0) {
coordinateSystem.reportYValue(record.takeProfit)
if (record.variable_current_position_takeProfit_value !== 0) {
coordinateSystem.reportYValue(record.variable_current_position_takeProfit_value)
}
/* Send the current record to the panel */
@@ -533,7 +524,7 @@
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
let eventRecords = {
currentRecord: record
record: record
};
thisObject.container.eventHandler.raiseEvent("Current Record Changed", eventRecords);
}
@@ -542,12 +533,12 @@
let takeProfitPhase = -1;
if (i > 0) {
if (record.stopLossPhase !== records[i - 1].stopLossPhase) {
stopLossPhase = record.stopLossPhase;
if (record.variable_current_position_stopLoss_phase !== records[i - 1].variable_current_position_stopLoss_phase) {
stopLossPhase = record.variable_current_position_stopLoss_phase;
}
if (record.takeProfitPhase !== records[i - 1].takeProfitPhase) {
takeProfitPhase = record.takeProfitPhase;
if (record.variable_current_position_takeProfit_phase !== records[i - 1].variable_current_position_takeProfit_phase) {
takeProfitPhase = record.variable_current_position_takeProfit_phase;
}
}
@@ -573,15 +564,15 @@
let recordPoint5 = {
x: record.begin,
y: record.stopLoss
y: record.variable_current_position_stopLoss_value
};
let recordPoint6 = {
x: record.end,
y: record.stopLoss
y: record.variable_current_position_stopLoss_value
};
if (record.stopLoss === 0) { // Put these points out of range if stopLoss is zero.
if (record.variable_current_position_stopLoss_value === 0) { // Put these points out of range if stopLoss is zero.
recordPoint5.x = 0;
recordPoint6.x = 0;
@@ -589,15 +580,15 @@
let recordPoint7 = {
x: record.begin,
y: record.sellRate
y: record.variable_current_position_rate
};
let recordPoint8 = {
x: record.end,
y: record.sellRate
y: record.variable_current_position_rate
};
if (record.sellRate === 0) { // Put these points out of range if sellRate is zero.
if (record.variable_current_position_rate === 0) { // Put these points out of range if sellRate is zero.
recordPoint7.x = 0;
recordPoint8.x = 0;
@@ -605,15 +596,15 @@
let recordPoint9 = {
x: record.begin,
y: record.takeProfit
y: record.variable_current_position_takeProfit_value
};
let recordPoint10 = {
x: record.end,
y: record.takeProfit
y: record.variable_current_position_takeProfit_value
};
if (record.takeProfit === 0) { // Put these points out of range if takeProfit is zero.
if (record.variable_current_position_takeProfit_value === 0) { // Put these points out of range if takeProfit is zero.
recordPoint9.x = 0;
recordPoint10.x = 0;
@@ -670,7 +661,7 @@
y: -30
}
let imageSize = (recordPoint2.x - recordPoint1.x) / 2;
let recordLabel = record.periods.toLocaleString()
let recordLabel = record.variable_episode_count_periods.toLocaleString()
if (imageSize < 8) {
if (recordLabel[recordLabel.length - 1] !== '0' || imageSize < 4)
recordLabel = ''
@@ -728,10 +719,10 @@
imageSize = 20;
let imageToDraw;
/* Depending on what is on top, it is also the text and image of the take profit / stop loss */
/* Depending on what is on top, it is also the text and image of the take accumulatedProfitLoss / stop loss */
let yOffset = 0
if (record.takeProfit > record.stopLoss) { yOffset = imageSize * 2 }
if (record.variable_current_position_takeProfit_value > record.variable_current_position_stopLoss_value) { yOffset = imageSize * 2 }
/* Next we are drawing the stopLoss floor / ceilling */
@@ -19,7 +19,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
container.frame.containerName = "Simulation Asset Balances Panel";
let currentRecord;
let record;
let lastRecord;
let upDownButton
@@ -56,7 +56,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
thisObject.onRecordChange = undefined
thisObject.isVisible = undefined
currentRecord = undefined
record = undefined
lastRecord = undefined
upDownButton = undefined
@@ -89,7 +89,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
function onRecordChange(records) {
currentRecord = records.currentRecord;
record = records.record;
lastRecord = records.lastRecord
}
@@ -117,7 +117,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
function plotCurrentRecordInfo() {
if (currentRecord === undefined) { return; }
if (record === undefined) { return; }
const frameBodyHeight = thisObject.container.frame.getBodyHeight();
const frameTitleHeight = thisObject.container.frame.height - frameBodyHeight;
@@ -139,7 +139,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
let paramsArray = []
let positionTaken = false
if (currentRecord.positionSize > 0) {
if (record.variable_current_position_size > 0) {
positionTaken = true
}
@@ -154,59 +154,59 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
return
}
if (currentRecord.baseAsset === currentRecord.marketBaseAsset) {
if (record.variable_episode_parameters_baseAsset === record.variable_episode_parameters_marketBaseAsset) {
params = {}
params.VALUE = currentRecord.balanceA;
params.INIT_VALUE = currentRecord.initialBalanceA
params.MIN_VALUE = currentRecord.minimunBalanceA
params.MAX_VALUE = currentRecord.maximunBalanceA
params.VALUE = record.variable_current_balance_baseAsset;
params.INIT_VALUE = record.variable_episode_parameters_initial_balance_baseAsset
params.MIN_VALUE = record.variable_episode_parameters_minimum_balance_baseAsset
params.MAX_VALUE = record.variable_episode_parameters_maximum_balance_baseAsset
params.ASSET_LABEL = 'Base'
params.ASSET_NAME = currentRecord.baseAsset
params.ASSET_NAME = record.variable_episode_parameters_baseAsset
params.LEFT_OFFSET = X_AXIS
params.POSITION_TAKEN = positionTaken
params.BASE_ASSET = currentRecord.baseAsset
params.BASE_ASSET = record.variable_episode_parameters_baseAsset
params.DECIMALS = 4
paramsArray.push(params)
params = {}
params.VALUE = currentRecord.balanceB;
params.MIN_VALUE = currentRecord.minimunBalanceB
params.INIT_VALUE = currentRecord.initialBalanceB
params.MAX_VALUE = currentRecord.maximunBalanceB
params.VALUE = record.variable_current_balance_quotedAsset;
params.MIN_VALUE = record.variable_episode_parameters_minimum_balance_quotedAsset
params.INIT_VALUE = record.variable_episode_parameters_initial_balance_quotedAsset
params.MAX_VALUE = record.variable_episode_parameters_maximum_balance_quotedAsset
params.ASSET_LABEL = 'Quoted'
params.ASSET_NAME = currentRecord.quotedAsset
params.ASSET_NAME = record.variable_episode_parameters_quotedAsset
params.LEFT_OFFSET = X_AXIS
params.POSITION_TAKEN = positionTaken
params.BASE_ASSET = currentRecord.baseAsset
params.BASE_ASSET = record.variable_episode_parameters_baseAsset
params.DECIMALS = 2
paramsArray.push(params)
} else {
params = {}
params.VALUE = currentRecord.balanceB;
params.INIT_VALUE = currentRecord.initialBalanceB
params.MIN_VALUE = currentRecord.minimunBalanceB
params.MAX_VALUE = currentRecord.maximunBalanceB
params.VALUE = record.variable_current_balance_quotedAsset;
params.INIT_VALUE = record.variable_episode_parameters_initial_balance_quotedAsset
params.MIN_VALUE = record.variable_episode_parameters_minimum_balance_quotedAsset
params.MAX_VALUE = record.variable_episode_parameters_maximum_balance_quotedAsset
params.ASSET_LABEL = 'Base'
params.ASSET_NAME = currentRecord.baseAsset
params.ASSET_NAME = record.variable_episode_parameters_baseAsset
params.LEFT_OFFSET = X_AXIS
params.POSITION_TAKEN = positionTaken
params.BASE_ASSET = currentRecord.baseAsset
params.BASE_ASSET = record.variable_episode_parameters_baseAsset
params.DECIMALS = 4
paramsArray.push(params)
params = {}
params.VALUE = currentRecord.balanceA;
params.MIN_VALUE = currentRecord.minimunBalanceA
params.INIT_VALUE = currentRecord.initialBalanceA
params.MAX_VALUE = currentRecord.maximunBalanceA
params.VALUE = record.variable_current_balance_baseAsset;
params.MIN_VALUE = record.variable_episode_parameters_minimum_balance_baseAsset
params.INIT_VALUE = record.variable_episode_parameters_initial_balance_baseAsset
params.MAX_VALUE = record.variable_episode_parameters_maximum_balance_baseAsset
params.ASSET_LABEL = 'Quoted'
params.ASSET_NAME = currentRecord.quotedAsset
params.ASSET_NAME = record.variable_episode_parameters_quotedAsset
params.LEFT_OFFSET = X_AXIS
params.POSITION_TAKEN = positionTaken
params.BASE_ASSET = currentRecord.baseAsset
params.BASE_ASSET = record.variable_episode_parameters_baseAsset
params.DECIMALS = 2
paramsArray.push(params)
@@ -21,7 +21,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
container.frame.containerName = "Simulation Current Position Panel";
let currentRecord;
let record;
let lastRecord;
let upDownButton
@@ -54,7 +54,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
thisObject.onRecordChange = undefined
thisObject.isVisible = undefined
currentRecord = undefined
record = undefined
lastRecord = undefined
upDownButton = undefined
}
@@ -84,7 +84,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
function onRecordChange(records) {
currentRecord = records.currentRecord;
record = records.record;
lastRecord = records.lastRecord
}
@@ -112,7 +112,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
function plotCurrentRecordInfo() {
if (currentRecord === undefined) { return; }
if (record === undefined) { return; }
const frameBodyHeight = thisObject.container.frame.getBodyHeight();
const frameTitleHeight = thisObject.container.frame.height - frameBodyHeight;
@@ -133,32 +133,32 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
y = y + increment;
printLabel('Size', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel(currentRecord.positionSize, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel(record.variable_current_position_size, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Rate', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel(currentRecord.sellRate, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel(record.variable_current_position_rate, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Stop', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel(currentRecord.stopLoss, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel(record.variable_current_position_stopLoss_value, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Take Profit', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel(currentRecord.takeProfit, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel(record.variable_current_position_takeProfit_value, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Periods', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel((currentRecord.positionPeriods), X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel((record.variable_current_position_count_periods), X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Days', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel((currentRecord.positionDays).toFixed(2), X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel((record.variable_current_position_stat_days).toFixed(2), X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
y = y + increment;
@@ -167,12 +167,12 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
y = y + increment;
printLabel('Profit / Loss', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel((currentRecord.lastTradeProfitLoss), X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel((record.variable_last_position_profitLoss), X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('ROI', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel((currentRecord.lastTradeROI).toFixed(2) + ' % ', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel((record.variable_last_position_ROI).toFixed(2) + ' % ', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
}
}
@@ -1,5 +1,5 @@

function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimulationPartialResultsPanel() {
function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimulationEpisodePanel() {
let thisObject = {
fitFunction: undefined,
@@ -17,9 +17,9 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
container.initialize();
thisObject.container = container;
container.frame.containerName = "Simulation Partial Results Panel";
container.frame.containerName = "Simulation Episode Panel";
let currentRecord;
let record;
let lastRecord;
let upDownButton
@@ -52,7 +52,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
thisObject.onRecordChange = undefined
thisObject.isVisible = undefined
currentRecord = undefined
record = undefined
lastRecord = undefined
upDownButton = undefined
}
@@ -82,7 +82,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
function onRecordChange(records) {
currentRecord = records.currentRecord;
record = records.record;
lastRecord = records.lastRecord
}
@@ -110,7 +110,7 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
function plotCurrentRecordInfo() {
if (currentRecord === undefined) { return; }
if (record === undefined) { return; }
const frameBodyHeight = thisObject.container.frame.getBodyHeight();
const frameTitleHeight = thisObject.container.frame.height - frameBodyHeight;
@@ -126,52 +126,52 @@ function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimul
y = y + increment;
y = y + increment;
printLabel('Partial Results', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel('Episode', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Profit / Loss', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel(currentRecord.profit, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel(record.variable_episode_stat_profitLoss, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Trades', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel(currentRecord.roundtrips, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel(record.variable_episode_count_positions, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Hits', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel(currentRecord.hits, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel(record.variable_episode_count_hits, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Fails', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel(currentRecord.fails, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel(record.variable_episode_count_fails, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Hit Ratio', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel((currentRecord.hitRatio * 100).toFixed(2) + ' %', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel((record.variable_episode_stat_hitRatio * 100).toFixed(2) + ' %', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('ROI', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel((currentRecord.ROI * 100).toFixed(2) + ' %', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel((record.variable_episode_stat_ROI * 100).toFixed(2) + ' %', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Periods', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel(currentRecord.periods, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel(record.variable_episode_count_periods, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Days', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel(currentRecord.days, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel(record.variable_episode_stat_days, X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel('Anualized Rate of Return', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction);
y = y + increment;
printLabel((currentRecord.anualizedRateOfReturn * 100).toFixed(2) + ' %', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
printLabel((record.variable_episode_stat_anualizedRateOfReturn * 100).toFixed(2) + ' %', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
}
}
+1 -1
View File
@@ -1 +1 @@
{"type":"Super Scripts","name":"Masters","code":"{ \n\"codeName\": \"Masters\"\n}","scriptsLibrary":{"type":"Scripts Library","name":"New Scripts Library","masterScripts":[{"type":"Master Script","name":"Setup Market","templateScripts":[{"type":"Template Script","name":"Install Single Market Data","templateStructure":{"type":"Template Structure","name":"New Template Structure","singleMarketData":{"type":"Single Market Data","name":"","dataProducts":[{"type":"Data Product","name":"Candles","id":"24c5f795-acf3-43c3-99ee-ddb521b082f4","savedPayload":{"position":{"x":39655.39345377463,"y":28084.121285348076},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Candles","id":"fe6065ec-4d2d-47a0-bae0-8647f0e195d7"}}},{"type":"Data Product","name":"Volumes","id":"204ec959-0861-486a-aa2a-276dbf48f775","savedPayload":{"position":{"x":39619.08803001109,"y":27971.34006849996},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Volumes","id":"1a366aef-efef-470e-88e0-2a6fbe4dd91f"}}},{"type":"Data Product","name":"Candles Channels","id":"90ee9733-ab7e-41a0-ac78-4a7661a27017","savedPayload":{"position":{"x":39594.11393185164,"y":27855.840877332517},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Candles Channels","id":"8c81d378-0947-4e9d-be25-58e69120152e"}}},{"type":"Data Product","name":"Candles Channels Objects","id":"9ade8e93-9071-422b-8cce-7a50d6dad739","savedPayload":{"position":{"x":39580.59887306321,"y":27738.507421368748},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Candles Channels Objects","id":"ba5dbb67-2030-42a0-9ff8-1ee80874f047"}}},{"type":"Data Product","name":"Bollinger Bands","id":"b5ef2cf7-3d35-45ec-848c-31970b59c04e","savedPayload":{"position":{"x":39578.655464896365,"y":27620.63069875915},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Bollinger Bands","id":"29088877-8d63-4217-8d34-8742afc262f4"}}},{"type":"Data Product","name":"Percentage Bandwidth","id":"1c3881ca-24b3-4cc9-b16b-9db7aa2b4c24","savedPayload":{"position":{"x":39588.297198778826,"y":27502.946480135615},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Percentage Bandwidth","id":"3b7885a0-cd72-4a3f-a38b-3dc8c47bd068"}}},{"type":"Data Product","name":"Bollinger Channels Objects","id":"92eec33b-86be-4b73-899f-e9550f7b0df3","savedPayload":{"position":{"x":39609.428887621216,"y":27386.77785099828},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Bollinger Channels Objects","id":"1f111f72-624f-4166-9f99-ab8d785d5267"}}},{"type":"Data Product","name":"Bollinger Sub-Channels Objects","id":"4b69df71-9091-4d22-9b0d-571304297033","savedPayload":{"position":{"x":39641.84608404141,"y":27273.24280350331},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Bollinger Sub-Channels Objects","id":"080c87fc-4546-4482-ab11-180a33f6d9ab"}}},{"type":"Data Product","name":"Popular SMAs","id":"8a5f7e27-9ca5-4d6e-b6b9-2d6cbdda8040","savedPayload":{"position":{"x":39685.2360649887,"y":27163.433854438405},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"PLine truncated
{"type":"Super Scripts","name":"Masters","code":"{ \n\"codeName\": \"Masters\"\n}","scriptsLibrary":{"type":"Scripts Library","name":"New Scripts Library","masterScripts":[{"type":"Master Script","name":"Setup Market","templateScripts":[{"type":"Template Script","name":"Install Single Market Data","templateStructure":{"type":"Template Structure","name":"New Template Structure","singleMarketData":{"type":"Single Market Data","name":"","dataProducts":[{"type":"Data Product","name":"Candles","id":"24c5f795-acf3-43c3-99ee-ddb521b082f4","savedPayload":{"position":{"x":39655.39345377463,"y":28084.121285348076},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Candles","id":"fe6065ec-4d2d-47a0-bae0-8647f0e195d7"}}},{"type":"Data Product","name":"Volumes","id":"204ec959-0861-486a-aa2a-276dbf48f775","savedPayload":{"position":{"x":39619.08803001109,"y":27971.34006849996},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Volumes","id":"1a366aef-efef-470e-88e0-2a6fbe4dd91f"}}},{"type":"Data Product","name":"Candles Channels","id":"90ee9733-ab7e-41a0-ac78-4a7661a27017","savedPayload":{"position":{"x":39594.11393185164,"y":27855.840877332517},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Candles Channels","id":"8c81d378-0947-4e9d-be25-58e69120152e"}}},{"type":"Data Product","name":"Candles Channels Objects","id":"9ade8e93-9071-422b-8cce-7a50d6dad739","savedPayload":{"position":{"x":39580.59887306321,"y":27738.507421368748},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Candles Channels Objects","id":"ba5dbb67-2030-42a0-9ff8-1ee80874f047"}}},{"type":"Data Product","name":"Bollinger Bands","id":"b5ef2cf7-3d35-45ec-848c-31970b59c04e","savedPayload":{"position":{"x":39578.655464896365,"y":27620.63069875915},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Bollinger Bands","id":"29088877-8d63-4217-8d34-8742afc262f4"}}},{"type":"Data Product","name":"Percentage Bandwidth","id":"1c3881ca-24b3-4cc9-b16b-9db7aa2b4c24","savedPayload":{"position":{"x":39588.297198778826,"y":27502.946480135615},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Percentage Bandwidth","id":"3b7885a0-cd72-4a3f-a38b-3dc8c47bd068"}}},{"type":"Data Product","name":"Bollinger Channels Objects","id":"92eec33b-86be-4b73-899f-e9550f7b0df3","savedPayload":{"position":{"x":39609.428887621216,"y":27386.77785099828},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Bollinger Channels Objects","id":"1f111f72-624f-4166-9f99-ab8d785d5267"}}},{"type":"Data Product","name":"Bollinger Sub-Channels Objects","id":"4b69df71-9091-4d22-9b0d-571304297033","savedPayload":{"position":{"x":39641.84608404141,"y":27273.24280350331},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Product Definition","name":"Bollinger Sub-Channels Objects","id":"080c87fc-4546-4482-ab11-180a33f6d9ab"}}},{"type":"Data Product","name":"Popular SMAs","id":"8a5f7e27-9ca5-4d6e-b6b9-2d6cbdda8040","savedPayload":{"position":{"x":39685.2360649887,"y":27163.433854438405},"targetPosition":{"x":40780.996436099675,"y":27659.843516028},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"PLine truncated
File diff suppressed because it is too large. Load diff
+35 -37
View File
@@ -2,8 +2,6 @@
const FULL_LOG = true;
const LOG_FILE_CONTENT = false;
const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
const ONE_MIN_IN_MILISECONDS = 60 * 1000;
const MODULE_NAME = "Commons";
@@ -12,7 +10,7 @@
validateOutputDatasets: validateOutputDatasets,
inflateDatafiles: inflateDatafiles,
dataBuildingProcedure: dataBuildingProcedure,
calculationsProcedure: calculationsProcedure,
calculationsProcedure: calculationsProcedure,
generateFileContent: generateFileContent,
writeFile: writeFile
};
@@ -25,15 +23,15 @@
function validateDataDependencies(dataDependencies, callBackFunction) {
for (let i = 0; i < dataDependencies.length; i++) {
let dataDependencyNode = dataDependencies[i]
let dataDependencyNode = dataDependencies[i]
/* Basic validations to see if we have everything we need. */
if (dataDependencyNode.referenceParent.parentNode.code.singularVariableName === undefined) {
if (dataDependencyNode.referenceParent.parentNode.config.singularVariableName === undefined) {
logger.write(MODULE_NAME, "[ERROR] start -> Product Definition without a Single Variable Name defined. Product Definition = " + JSON.stringify(dataDependencyNode.referenceParent.parentNode));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
}
if (dataDependencyNode.referenceParent.parentNode.code.pluralVariableName === undefined) {
if (dataDependencyNode.referenceParent.parentNode.config.pluralVariableName === undefined) {
logger.write(MODULE_NAME, "[ERROR] start -> Product Definition without a Plural Variable Name defined. Product Definition = " + JSON.stringify(dataDependencyNode.referenceParent.parentNode));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
@@ -61,12 +59,12 @@
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
}
if (outputDatasetNode.referenceParent.parentNode.code.singularVariableName === undefined) {
if (outputDatasetNode.referenceParent.parentNode.config.singularVariableName === undefined) {
logger.write(MODULE_NAME, "[ERROR] start -> Product Definition without a Single Variable Name defined. Product Definition = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
}
if (outputDatasetNode.referenceParent.parentNode.code.pluralVariableName === undefined) {
if (outputDatasetNode.referenceParent.parentNode.config.pluralVariableName === undefined) {
logger.write(MODULE_NAME, "[ERROR] start -> Product Definition without a Plural Variable Name defined. Product Definition = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
@@ -79,7 +77,7 @@
if (outputDatasetNode.referenceParent.parentNode.dataBuilding === undefined) {
logger.write(MODULE_NAME, "[WARN] start -> Product Definition " + outputDatasetNode.referenceParent.parentNode.name + " without a Data Building Procedure. Product Definition = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode));
}
if (outputDatasetNode.referenceParent.code.codeName === undefined) {
if (outputDatasetNode.referenceParent.config.codeName === undefined) {
logger.write(MODULE_NAME, "[ERROR] start -> Dataset witn no codeName defined. Product Dataset = " + JSON.stringify(outputDatasetNode.referenceParent));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
@@ -91,7 +89,7 @@
return
}
if (outputDatasetNode.referenceParent.parentNode.code.codeName === undefined) {
if (outputDatasetNode.referenceParent.parentNode.config.codeName === undefined) {
logger.write(MODULE_NAME, "[ERROR] start -> Product Definition witn no codeName defined. Product Definition = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
@@ -103,7 +101,7 @@
return
}
if (outputDatasetNode.referenceParent.parentNode.parentNode.code.codeName === undefined) {
if (outputDatasetNode.referenceParent.parentNode.parentNode.config.codeName === undefined) {
logger.write(MODULE_NAME, "[ERROR] start -> Bot witn no codeName defined. Bot = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode.parentNode));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
@@ -115,7 +113,7 @@
return
}
if (outputDatasetNode.referenceParent.parentNode.parentNode.parentNode.code.codeName === undefined) {
if (outputDatasetNode.referenceParent.parentNode.parentNode.parentNode.config.codeName === undefined) {
logger.write(MODULE_NAME, "[ERROR] start -> Data Mine witn no codeName defined. Data Mine = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode.parentNode.parentNode));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
@@ -132,19 +130,19 @@
*/
for (let i = 0; i < dataDependencies.length; i++) {
let dataFile
let dataFile
let jsonData // Datafile converted into Json objects
let inputData // Includes calculated properties
let singularVariableName // name of the variable for this product
let recordDefinition
let dataDependencyNode = dataDependencies[i]
let dataDependencyNode = dataDependencies[i]
dataFile = dataFiles.get(dataDependencyNode.id)
if (dataFile === undefined) { continue } // When a datafile is not found it might be because we are processing market or daily and at the dependency array there are both types mixed up.
recordDefinition = dataDependencyNode.referenceParent.parentNode.record
singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName
singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName
/* Transform the raw data into JSON objects */
jsonData = jsonifyDataFile(dataFile, recordDefinition)
/* Add the calculated properties */
@@ -153,7 +151,7 @@
} else {
inputData = jsonData
}
products[dataDependencyNode.referenceParent.parentNode.code.pluralVariableName] = inputData
products[dataDependencyNode.referenceParent.parentNode.config.pluralVariableName] = inputData
/* The main dependency is defined as the first dependency processed. */
if (mainDependency.records === undefined) {
@@ -177,8 +175,8 @@
let record = {}
for (let j = 0; j < recordDefinition.properties.length; j++) {
let property = recordDefinition.properties[j]
if (property.code.isCalculated !== true) {
record[property.code.codeName] = dataFile[i][j]
if (property.config.isCalculated !== true) {
record[property.config.codeName] = dataFile[i][j]
}
}
@@ -199,7 +197,7 @@
let system = { // These are the available system variables to be used in User Code and Formulas
timeFrame: timeFrame,
ONE_DAY_IN_MILISECONDS: ONE_DAY_IN_MILISECONDS
ONE_DAY_IN_MILISECONDS: global.ONE_DAY_IN_MILISECONDS
}
let variable = {} // This is the structure where the user will define its own variables that will be shared across different code blocks and formulas.
let results = []
@@ -238,13 +236,13 @@
/* For each calculated property we apply its formula*/
for (let j = 0; j < recordDefinition.properties.length; j++) {
let property = recordDefinition.properties[j]
if (property.code.isCalculated === true) {
if (property.config.isCalculated === true) {
if (property.formula !== undefined) {
if (property.formula.code !== undefined) {
try {
let newValue = eval(property.formula.code)
let currentRecord = product[variableName]
currentRecord[property.code.codeName] = newValue
currentRecord[property.config.codeName] = newValue
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. Error = " + err.stack)
logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. product = " + JSON.stringify(product))
@@ -277,7 +275,7 @@
interExecutionMemory,
processingDailyFiles,
currentDay
) {
) {
/*
This function has as an input the products object, with all the information
@@ -286,12 +284,12 @@
a new set of information.
*/
let lastInstantOfTheDay
let lastInstantOfTheDay
let yesterday = {}
let system = { // These are the available system variables to be used in User Code and Formulas
timeFrame: timeFrame,
ONE_DAY_IN_MILISECONDS: ONE_DAY_IN_MILISECONDS,
ONE_MIN_IN_MILISECONDS: ONE_MIN_IN_MILISECONDS
ONE_DAY_IN_MILISECONDS: global.ONE_DAY_IN_MILISECONDS,
ONE_MIN_IN_MILISECONDS: global.ONE_MIN_IN_MILISECONDS
}
let variable = {} // This is the structure where the user will define its own variables that will be shared across different code blocks and formulas.
let results = []
@@ -313,7 +311,7 @@
let dataDependencyMap = new Map()
for (let j = 0; j < dataDependecyArray.length; j++) {
let record = dataDependecyArray[j]
let key = record.begin.toString() + '-' + record.end.toString()
let key = record.begin.toString() + '-' + record.end.toString()
dataDependencyMap.set(key, record)
}
dataDependencies[dataDependencyName] = dataDependencyMap
@@ -321,7 +319,7 @@
}
function getElement(dependencyName, currentRecordPrimaryDataDependency) {
let key = currentRecordPrimaryDataDependency.begin.toString() + '-' + currentRecordPrimaryDataDependency.end.toString()
let key = currentRecordPrimaryDataDependency.begin.toString() + '-' + currentRecordPrimaryDataDependency.end.toString()
return dataDependencies[dependencyName].get(key)
}
@@ -340,7 +338,7 @@
if (processingDailyFiles) {
/* Initialization of Last Instance */
lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1;
lastInstantOfTheDay = currentDay.valueOf() + global.ONE_DAY_IN_MILISECONDS - 1;
if (interExecutionMemory[productName] === undefined) {
/* The first time the intialization variables goes to the Inter Execution Memory. */
@@ -349,7 +347,7 @@
}
else {
/* We override the initialization, since the valid stuff is already at the Inter Execution Memory */
variable = JSON.parse(JSON.stringify(interExecutionMemory[productName].variable))
variable = JSON.parse(JSON.stringify(interExecutionMemory[productName].variable))
}
}
@@ -387,13 +385,13 @@
/* For each non-calculated property we apply its formula*/
for (let j = 0; j < recordDefinition.properties.length; j++) {
let property = recordDefinition.properties[j]
if (property.code.isCalculated !== true) {
if (property.config.isCalculated !== true) {
if (property.formula !== undefined) {
if (property.formula.code !== undefined) {
try {
let newValue = eval(property.formula.code)
let currentRecord = product[variableName]
currentRecord[property.code.codeName] = newValue
currentRecord[property.config.codeName] = newValue
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> formula -> Error executing User Code. Error = " + err.stack)
logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> formula -> Error executing User Code. product = " + JSON.stringify(product))
@@ -411,7 +409,7 @@
results.push(product[variableName]);
}
/* While we are positioned at Yesterday, we keey updating this data structure. */
/* While we are positioned at Yesterday, we keep updating this data structure. */
if (processingDailyFiles) {
if (positionedAtYesterday) {
yesterday.variable = JSON.parse(JSON.stringify(variable))
@@ -457,7 +455,7 @@
at the next day, in whole, even if it starts in the previous day.
*/
let lastInstantOdDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1;
let lastInstantOdDay = currentDay.valueOf() + global.ONE_DAY_IN_MILISECONDS - 1;
if (record.end < currentDay.valueOf() - 1) { continue; }
if (record.end === lastInstantOdDay) { continue; }
@@ -474,13 +472,13 @@
let propertySeparator = ""
for (let j = 0; j < recordDefinition.properties.length; j++) {
let property = recordDefinition.properties[j]
if (property.code.isCalculated !== true) {
if (property.config.isCalculated !== true) {
fileContent = fileContent + propertySeparator
if (property.code.isString === true) {
if (property.config.isString === true) {
fileContent = fileContent + '"'
}
fileContent = fileContent + record[property.code.codeName]
if (property.code.isString === true) {
fileContent = fileContent + record[property.config.codeName]
if (property.config.isString === true) {
fileContent = fileContent + '"'
}
if (propertySeparator === "") { propertySeparator = ","; }
-551
View File
@@ -1,551 +0,0 @@
exports.newContext = function newContext(BOT, logger, UTILITIES) {
let bot = BOT;
const MODULE_NAME = "Context";
/*
This module deals with keeping the context between different executions of the bot. Conceptually this context is divided in 3 main parts:
I. The non-business information which helps the mechanisms of giving continuety to the bots execution over time. This information goes in a file
called the Status Report, and there is a module, child of this one called Status Report that deals with loading and saving the contents of that file.
II. The business information around the bot execution, including its balance, positions at exchanges, trades executed and many other things. These
are platform data mantained on behalf of the executing bot. All these is kept in one file per execution called the Execution Context. The collection
of all these files can later reconstruct the vital business information the bot had at each moment in time.
II. Execution of any bot cannot be guaranteed that will be on fixed interval of times. We need an index of all executions that points to the detailed files
with all the business informatino the bot had each time it executed. We call this index the Execution History and there is one file to store it.
*/
let thisObject = {
statusReport: undefined, // Here is the information that defines which was the last sucessfull execution and some other details.
executionHistory: [], // This is the record of bot execution.
executionContext: undefined, // Here is the business information of the last execution of this bot process.
newHistoryRecord : {
date: undefined,
buyAvgRate: 0,
sellAvgRate: 0,
lastSellRate: 0,
sellExecRate: 0,
lastBuyRate: 0,
buyExecRate: 0,
marketRate: 0,
newPositions: 0,
newTrades: 0,
movedPositions: 0,
profitsBaseAsset: 0,
profitsQuotedAsset: 0,
combinedProfitsA: 0,
combinedProfitsB: 0,
messageRelevance: 0,
messageTitle: "",
messageBody: ""
},
initialize: initialize,
saveThemAll: saveThemAll,
extraData: []
};
/*
During the process we will create a new History Record. This will go to the Context History file which essentially mantains an
index of all the bots executions. This file will later be plotted by the bot s plotter on the timeline, allowing end users to
know where there is information related to the actions taken by the bot.
*/
let statusReportModule;
/* Utilities needed. */
let utilities = UTILITIES.newCloudUtilities(logger);
/* Storage account to be used here. */
const FILE_STORAGE = require('./FileStorage.js');
let fileStorage = FILE_STORAGE.newFileStorage(logger);
let statusDependencies;
let runIndex; // This is the index for this run and depends on the startMode.
let sessionPath = ''
return thisObject;
function initialize(pStatusDependencies, callBackFunction) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
statusDependencies = pStatusDependencies;
if (bot.SESSION !== undefined) {
sessionPath = bot.SESSION.folderName + "/"
}
/*
Here we get the positions the bot did and that are recorded at the bot storage account. We will use them through out the rest
of the process.
*/
thisObject.newHistoryRecord.date = bot.processDatetime;
getStatusReport(onDone);
function onDone(err) {
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> onDone -> Execution finished well."); }
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> Retry Later. Requesting Execution Retry.");
callBackFunction(err);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> Operation Failed. Aborting the process.");
callBackFunction(err);
return;
}
default: {
logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> Operation Failed with custom response.");
logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> err = " + JSON.stringify(err));
callBackFunction(err);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> err = "+ err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function getStatusReport(callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getStatusReport -> Entering function."); }
let key = bot.dataMine + "-" + bot.codeName + "-" + "Context" + "-" + bot.dataSetVersion;
statusReportModule = statusDependencies.statusReports.get(key);
thisObject.statusReport = statusReportModule.file;
/* The context is created in 2 situations: 1) when at the bot config is set not to continue using the same context after a new execution. 2) when the status report does not exist. */
if (bot.hasTheBotJustStarted === true || thisObject.statusReport.runs === undefined) {
createConext(callBack);
} else {
runIndex = thisObject.statusReport.runs.length - 1;
getExecutionHistory(callBack);
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> getStatusReport -> err = "+ err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function getExecutionHistory(callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getExecutionHistory -> Entering function."); }
let fileName = "Execution.History." + bot.startMode + "." + runIndex + ".json";
let filePath = bot.filePathRoot + "/Output/" + sessionPath + "Trading-Process/" + fileName;
fileStorage.getTextFile(filePath, onFileReceived);
function onFileReceived(err, text) {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionHistory -> onFileReceived -> err = "+ JSON.stringify(err));
callBack(err);
return;
}
if (global.LOG_CONTROL[MODULE_NAME].logContent === true) {
logger.write(MODULE_NAME, "[INFO] initialize -> getExecutionHistory -> onFileReceived -> Content received = " + text);
}
try {
thisObject.executionHistory = JSON.parse(text);
/* Move some values to the new record, in case there are no transactions that re-calculate them. */
thisObject.newHistoryRecord.buyAvgRate = thisObject.executionHistory[thisObject.executionHistory.length-1][1];
thisObject.newHistoryRecord.sellAvgRate = thisObject.executionHistory[thisObject.executionHistory.length - 1][2];
getExecutionContext(callBack);
} catch (err) {
/*
It might happen that the file content is corrupt or it does not exist. The bot can not run without an Execution Hitory,
since it is risky to ignore its own history unless it is its first execution in this mode ever.
*/
logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionHistory -> onFileReceived -> Bot cannot execute without the Execution History. -> Err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionHistory -> err = "+ err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function getExecutionContext(callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getExecutionContext -> Entering function."); }
let date;
date = new Date(thisObject.statusReport.runs[runIndex].lastExecution);
thisObject.statusReport.runs[runIndex].lastExecution = bot.processDatetime;
thisObject.statusReport.runs[runIndex].endDatetime = bot.processDatetime;
let fileName = "/Execution.Context." + bot.startMode + "." + runIndex + ".json";
let dateForPath = date.getUTCFullYear() + '/' + utilities.pad(date.getUTCMonth() + 1, 2) + '/' + utilities.pad(date.getUTCDate(), 2) + '/' + utilities.pad(date.getUTCHours(), 2) + '/' + utilities.pad(date.getUTCMinutes(), 2);
let filePath = bot.filePathRoot + "/Output/" + sessionPath + "Trading-Process/" + dateForPath + fileName;
fileStorage.getTextFile(filePath, onFileReceived);
function onFileReceived(err, text) {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionContext -> onFileReceived -> err = "+ err.stack);
callBack(err);
return;
}
if (global.LOG_CONTROL[MODULE_NAME].logContent === true) {
logger.write(MODULE_NAME, "[INFO] initialize -> getExecutionContext -> onFileReceived -> Content received = " + text);
}
try {
thisObject.executionContext = JSON.parse(text);
thisObject.executionContext.transactions = []; // We record here the transactions that happened duting this execution.
/* Update the new History Record, in case there are no trades during this execution that updates it. */
thisObject.newHistoryRecord.profitsBaseAsset = thisObject.executionContext.profits.baseAsset;
thisObject.newHistoryRecord.profitsQuotedAsset = thisObject.executionContext.profits.quotedAsset;
thisObject.newHistoryRecord.combinedProfitsA = thisObject.executionContext.combinedProfits.baseAsset;
thisObject.newHistoryRecord.combinedProfitsB = thisObject.executionContext.combinedProfits.quotedAsset;
callBack(global.DEFAULT_OK_RESPONSE);
} catch (err) {
/*
It might happen that the file content is corrupt or it does not exist. The bot can not run without a Status Report,
since it is risky to ignore its own execution history. Except when the bot is running for the fist time in this mode,
an execution context file with the right format is needed.
*/
logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionContext -> onFileReceived -> Response from storage. -> Text = " + text);
logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionContext -> onFileReceived -> Bot cannot execute without the Execution Context. -> Err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionContext -> err = "+ err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function createConext(callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> createConext -> Entering function."); }
/*
When the bot is executed for the very first time, there are a few files that do not exist and need to be created, and that
content is what we are going to set up now.
*/
if (thisObject.statusReport.runs === undefined) { // This means that the Status Report does not exist.
thisObject.statusReport.runs = [];
}
let runContent = {
beginDatetime: bot.processDatetime,
endDatetime: bot.processDatetime,
lastExecution: bot.processDatetime
};
thisObject.statusReport.runs.push(runContent);
runIndex = thisObject.statusReport.runs.length - 1;
thisObject.executionHistory = [];
if (bot.VALUES_TO_USE.initialBalanceA === undefined || bot.VALUES_TO_USE.initialBalanceB === undefined) { throw new Error("Global Variables INITIAL_BALANCE_A and INITIAL_BALANCE_B cannot be undefined.") }
const INITIAL_BALANCE_A = Number(bot.VALUES_TO_USE.initialBalanceB); // NOTE THAT THIS IS INVERTED BECAUSE OF POLONIEX THAT IS THE ONLY EXCHANGE SUPPORTED RIGHT NOW
const INITIAL_BALANCE_B = Number(bot.VALUES_TO_USE.initialBalanceA);
thisObject.executionContext = {
initialBalance: { // This is used to calculate profits.
baseAsset: INITIAL_BALANCE_A,
quotedAsset: INITIAL_BALANCE_B
},
balance: { // This is the total balance that includes positions at the order book + funds available to be traded.
baseAsset: INITIAL_BALANCE_A,
quotedAsset: INITIAL_BALANCE_B // It starts with the initial initialBalance.
},
availableBalance: { // This is the balance the bot has at any moment in time available to be traded (not in positions at the order book).
baseAsset: INITIAL_BALANCE_A,
quotedAsset: INITIAL_BALANCE_B // It starts with the initial initialBalance.
},
profits: {
baseAsset: 0,
quotedAsset: 0
},
combinedProfits: {
baseAsset: 0,
quotedAsset: 0
},
positions: [],
transactions: []
};
callBack(global.DEFAULT_OK_RESPONSE);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> createConext -> err = "+ err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> err = "+ err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function saveThemAll(callBackFunction) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> Entering function."); }
writeExecutionContext(onDone);
function onDone(err) {
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> onDone -> Execution finished well."); }
bot.hasTheBotJustStarted = false;
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
break;
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[ERROR] saveThemAll -> onDone -> Retry Later. Requesting Execution Retry.");
callBackFunction(err);
return;
}
break;
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] saveThemAll -> onDone -> Operation Failed. Aborting the process.");
callBackFunction(err);
return;
}
break;
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] saveThemAll -> onDone -> err = "+ err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function writeExecutionContext(callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExecutionContext -> Entering function."); }
let fileName = "/Execution.Context." + bot.startMode + "." + runIndex +".json";
let dateForPath = bot.processDatetime.getUTCFullYear() + '/' + utilities.pad(bot.processDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.processDatetime.getUTCDate(), 2) + '/' + utilities.pad(bot.processDatetime.getUTCHours(), 2) + '/' + utilities.pad(bot.processDatetime.getUTCMinutes(), 2);
let filePath = bot.filePathRoot + "/Output/" + sessionPath + "Trading-Process/" + dateForPath + fileName;
let fileContent = JSON.stringify(thisObject.executionContext);
if(fileContent === undefined){
logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExecutionContext -> executionContext is undefined.");
callBackFunction(global.DEFAULT_ERROR_RESPONSE);
}
if (global.LOG_CONTROL[MODULE_NAME].logContent === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExecutionContext -> fileContent = " + fileContent); }
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
function onFileCreated(err) {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExecutionContext -> onFileCreated -> Entering function."); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExecutionContext -> onFileCreated -> err = "+ err.stack);
callBack(err);
return;
}
writeExucutionHistory(callBack);
return;
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExecutionContext -> err = "+ err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function writeExucutionHistory(callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExucutionHistory -> Entering function."); }
let fileName = "Execution.History." + bot.startMode + "." + runIndex + ".json";
let filePath = bot.filePathRoot + "/Output/" + sessionPath + "Trading-Process/" + fileName;
let newRecord = [
thisObject.newHistoryRecord.date.valueOf(),
thisObject.newHistoryRecord.buyAvgRate,
thisObject.newHistoryRecord.sellAvgRate,
thisObject.newHistoryRecord.lastSellRate,
thisObject.newHistoryRecord.sellExecRate,
thisObject.newHistoryRecord.lastBuyRate,
thisObject.newHistoryRecord.buyExecRate,
thisObject.newHistoryRecord.marketRate,
thisObject.newHistoryRecord.newPositions,
thisObject.newHistoryRecord.newTrades,
thisObject.newHistoryRecord.movedPositions,
thisObject.newHistoryRecord.profitsBaseAsset,
thisObject.newHistoryRecord.profitsQuotedAsset,
thisObject.newHistoryRecord.combinedProfitsA,
thisObject.newHistoryRecord.combinedProfitsB,
thisObject.newHistoryRecord.messageRelevance,
thisObject.newHistoryRecord.messageTitle,
thisObject.newHistoryRecord.messageBody,
thisObject.extraData
];
thisObject.executionHistory.push(newRecord);
let fileContent = JSON.stringify(thisObject.executionHistory);
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
function onFileCreated(err) {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExucutionHistory -> onFileCreated -> Entering function."); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExucutionHistory -> onFileCreated -> err = "+ err.stack);
callBack(err);
return;
}
if (global.LOG_CONTROL[MODULE_NAME].logContent === true) {
logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExucutionHistory -> onFileCreated -> Content written = " + fileContent);
}
/* Here we will write the file containing the max sequence number. */
fileContent = runIndex;
fileName = "Execution.History." + bot.startMode + "." + "Sequence" + ".json";
filePath = bot.filePathRoot + "/Output/" + sessionPath + "Trading-Process/" + fileName;
fileStorage.createTextFile(filePath, fileContent + '\n', onSequenceFileCreated);
function onSequenceFileCreated(err) {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExucutionHistory -> onFileCreated -> onSequenceFileCreated -> Entering function."); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExucutionHistory -> onFileCreated -> onSequenceFileCreated -> err = "+ err.stack);
callBack(err);
return;
}
writeStatusReport(callBack);
return;
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExucutionHistory -> err = "+ err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function writeStatusReport(callBack) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeStatusReport -> Entering function."); }
statusReportModule.file = thisObject.statusReport;
statusReportModule.save(callBack);
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeStatusReport -> err = "+ err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] saveThemAll -> Error = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function truncDecimals(pFloatValue, pDecimals) {
if (!pDecimals) pDecimals = 8; // Default value
return parseFloat(parseFloat(pFloatValue).toFixed(pDecimals));
}
};
+17 -17
View File
@@ -16,7 +16,7 @@ exports.newDataSet = function newDataSet(BOT, logger) {
/* Storage account to be used here. */
const FILE_STORAGE = require('./FileStorage.js');
let fileStorage
let fileStorage
return thisObject;
@@ -36,7 +36,7 @@ exports.newDataSet = function newDataSet(BOT, logger) {
return
}
if (thisObject.node.code.codeName === undefined) {
if (thisObject.node.config.codeName === undefined) {
logger.write(MODULE_NAME, "[ERROR] initialize -> Dataset witn no codeName defined -> Product Dataset = " + JSON.stringify(thisObject.node));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
@@ -48,7 +48,7 @@ exports.newDataSet = function newDataSet(BOT, logger) {
return
}
if (thisObject.node.parentNode.code.codeName === undefined) {
if (thisObject.node.parentNode.config.codeName === undefined) {
logger.write(MODULE_NAME, "[ERROR] initialize -> Product Definition witn no codeName defined -> Product Definition = " + JSON.stringify(thisObject.node.parentNode));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
@@ -60,7 +60,7 @@ exports.newDataSet = function newDataSet(BOT, logger) {
return
}
if (thisObject.node.parentNode.parentNode.code.codeName === undefined) {
if (thisObject.node.parentNode.parentNode.config.codeName === undefined) {
logger.write(MODULE_NAME, "[ERROR] initialize -> Bot witn no codeName defined. Bot = " + JSON.stringify(thisObject.node.parentNode.parentNode));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
@@ -72,14 +72,14 @@ exports.newDataSet = function newDataSet(BOT, logger) {
return
}
if (thisObject.node.parentNode.parentNode.parentNode.code.codeName === undefined) {
if (thisObject.node.parentNode.parentNode.parentNode.config.codeName === undefined) {
logger.write(MODULE_NAME, "[ERROR] initialize -> Data Mine witn no codeName defined. Data Mine = " + JSON.stringify(thisObject.node.parentNode.parentNode.parentNode));
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
}
/* Now we will see where do we need to fetch this data from. */
let network = global.TASK_NETWORK
let network = global.TASK_NETWORK
let datasetProductDefinition = thisObject.node.parentNode
for (let i = 0; i < network.networkNodes.length; i++) {
@@ -102,9 +102,9 @@ exports.newDataSet = function newDataSet(BOT, logger) {
if (datasetProductDefinition.id === productDefinition.id) {
/* We found where the data is located on the network. */
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Retrieving data from " + networkNode.name + " -> host = " + networkNode.code.host + ' -> port = ' + networkNode.code.webPort + '.'); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Retrieving data from " + networkNode.name + " -> host = " + networkNode.config.host + ' -> port = ' + networkNode.config.webPort + '.'); }
fileStorage = FILE_STORAGE.newFileStorage(logger, networkNode.code.host, networkNode.code.webPort);
fileStorage = FILE_STORAGE.newFileStorage(logger, networkNode.config.host, networkNode.config.webPort);
callBackFunction(global.DEFAULT_OK_RESPONSE);
return
}
@@ -133,9 +133,9 @@ exports.newDataSet = function newDataSet(BOT, logger) {
if (datasetProductDefinition.id === productDefinition.id) {
/* We found where the data is located on the network. */
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Retrieving data from " + networkNode.name + " -> host = " + networkNode.code.host + ' -> port = ' + networkNode.code.webPort + '.'); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Retrieving data from " + networkNode.name + " -> host = " + networkNode.config.host + ' -> port = ' + networkNode.config.webPort + '.'); }
fileStorage = FILE_STORAGE.newFileStorage(logger, networkNode.code.host, networkNode.code.webPort);
fileStorage = FILE_STORAGE.newFileStorage(logger, networkNode.config.host, networkNode.config.webPort);
callBackFunction(global.DEFAULT_OK_RESPONSE);
return
}
@@ -155,7 +155,7 @@ exports.newDataSet = function newDataSet(BOT, logger) {
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
@@ -173,8 +173,8 @@ exports.newDataSet = function newDataSet(BOT, logger) {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTextFile -> Entering function."); }
let dataMineCodeName = thisObject.node.parentNode.parentNode.parentNode.code.codeName
let botCodeName = thisObject.node.parentNode.parentNode.code.codeName
let dataMineCodeName = thisObject.node.parentNode.parentNode.parentNode.config.codeName
let botCodeName = thisObject.node.parentNode.parentNode.config.codeName
let filePathRoot = bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset + "/" + dataMineCodeName + "/" + botCodeName;
let filePath = filePathRoot + "/Output/" + pFolderPath;
@@ -191,7 +191,7 @@ exports.newDataSet = function newDataSet(BOT, logger) {
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] 'getTextFile' -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] 'getTextFile' -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
@@ -204,8 +204,8 @@ exports.newDataSet = function newDataSet(BOT, logger) {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createTextFile -> pFolderPath = " + pFolderPath); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createTextFile -> pFileName = " + pFileName); }
let ownerId = thisObject.node.dataMine + "-" + thisObject.node.bot + "-" + thisObject.node.botVersion.major + "-" + thisObject.node.botVersion.minor + "-" + thisObject.node.dataSetVersion;
let botId = bot.dataMine + "-" + bot.codeName + "-" + bot.version.major + "-" + bot.version.minor + "-" + bot.dataSetVersion;
let ownerId = thisObject.node.dataMine + "-" + thisObject.node.bot
let botId = bot.dataMine + "-" + bot.codeName
if (ownerId !== botId) {
@@ -232,7 +232,7 @@ exports.newDataSet = function newDataSet(BOT, logger) {
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] 'createTextFile' -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] 'createTextFile' -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
+13 -16
View File
@@ -1,6 +1,5 @@
exports.newDebugLog = function newDebugLog() {
const ROOT_DIR = './';
const MODULE_NAME = "DebugLog";
let executionDatetime = "D." + global.EXECUTION_DATETIME.getUTCFullYear() +
@@ -34,7 +33,7 @@ exports.newDebugLog = function newDebugLog() {
disableLogging = pdisableLogging
} catch (err) {
console.log("[ERROR] Debug Log -> initialize -> err = "+ err.stack);
console.log("[ERROR] Debug Log -> initialize -> err = " + err.stack);
}
}
@@ -53,12 +52,12 @@ exports.newDebugLog = function newDebugLog() {
date = date.getUTCFullYear() + '-' + strPad(date.getUTCMonth() + 1, 2, "0") + '-' + strPad(date.getUTCDate(), 2, "0");
console.log(new Date().toISOString() + " " + strPad(thisObject.bot.exchange, 20) + " " + strPad(thisObject.bot.market.baseAsset + '/' + thisObject.bot.market.quotedAsset, 10) + " " + strPad(pBot, 30) + " " + strPad(pProcess, 30)
+ " Internal Loop # " + strPad(internalLoopCounter + 1, 8) + " " + strPad(date, 30) + " " + strPad(percentage, 10))
+ " Internal Loop # " + strPad(internalLoopCounter + 1, 8) + " " + strPad(date, 30) + " " + strPad(percentage, 10))
persist();
function strPad(str, max, fill) {
if (fill === undefined) {fill = " "}
if (fill === undefined) { fill = " " }
str = str.toString();
return str.length < max ? strPad(fill + str, max) : str;
}
@@ -69,7 +68,7 @@ exports.newDebugLog = function newDebugLog() {
/* Here we actually write the content of the in-memory log to a file */
try {
if (accumulatedLog === "[") {return} // nothing to persist at the moment.
if (accumulatedLog === "[") { return } // nothing to persist at the moment.
internalLoopCounter++;
@@ -82,7 +81,7 @@ exports.newDebugLog = function newDebugLog() {
let filePath = thisObject.bot.filePathRoot + "/Logs/" + thisObject.bot.process + "/"
if (thisObject.bot.SESSION !== undefined) {
filePath = filePath + thisObject.bot.SESSION.folderName + "/" + executionDatetime;
filePath = filePath + thisObject.bot.SESSION.folderName + "/" + executionDatetime;
} else {
filePath = filePath + executionDatetime;
}
@@ -102,32 +101,32 @@ exports.newDebugLog = function newDebugLog() {
writeLog();
/* This is the implementation of the mechanism to auto-mantain logs. */
if (contentToPersist.indexOf('[ERROR]') < 0) {
if (contentToPersist.indexOf('[ERROR]') < 0 && contentToPersist.indexOf('[PERSIST]') < 0) {
thisObject.bot.LOGS_TO_DELETE_QUEUE.push(filePath + '/' + fileName)
}
if (thisObject.bot.LOGS_TO_DELETE_QUEUE.length > thisObject.bot.DELETE_QUEUE_SIZE) {
let fileToDelete = thisObject.bot.LOGS_TO_DELETE_QUEUE[0]
thisObject.bot.LOGS_TO_DELETE_QUEUE.splice(0, 1)
/* Will delete this file only if it does not contains ERROR inside. */
let fileContent = fileStorage.getTextFile(fileToDelete, onGetFile, true)
let fileContent = fileStorage.getTextFile(fileToDelete, onGetFile, true)
function onGetFile(err, fileContent) {
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
if (fileContent.indexOf("ERROR") < 0) {
/* Logs will only be deleted when they contain no ERROR in them. */
fileStorage.deleteTextFile(fileToDelete);
}
}
} else {
fileStorage.deleteTextFile(fileToDelete);
}
}
}
function writeLog() {
fileStorage.createTextFile(filePath + '/' + fileName, contentToPersist + '\r\n' + "]", onFileCreated);
fileStorage.createTextFile(filePath + '/' + fileName, contentToPersist + '\r\n' + "]", onFileCreated, undefined, true);
function onFileCreated(err) {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
console.log("[ERROR] DebugLog -> persist -> onInizialized -> onFileCreated -> err = "+ err.message);
console.log("[ERROR] DebugLog -> persist -> onInizialized -> onFileCreated -> err = " + err.message);
setTimeout(writeLog, 10000); // Lets retry until we make it.
return;
}
@@ -135,16 +134,14 @@ exports.newDebugLog = function newDebugLog() {
}
}
} catch (err) {
console.log("[ERROR] DebugLog -> persist -> err = "+ err.stack);
console.log("[ERROR] DebugLog -> persist -> err = " + err.stack);
console.log("[ERROR] DebugLog -> persist -> onInizialized -> contentToPersist = " + contentToPersist);
}
}
function write(pModule, pMessage) {
try {
if (disableLogging === true) { return; }
if (thisObject.bot === undefined) { return; }
@@ -174,7 +171,7 @@ exports.newDebugLog = function newDebugLog() {
accumulatedLog = accumulatedLog + logLine;
} catch (err) {
console.log("[ERROR] DebugLog -> write -> err = "+ err.stack);
console.log("[ERROR] DebugLog -> write -> err = " + err.stack);
}
}
+8 -16
View File
@@ -1,5 +1,5 @@
exports.newExchangeAPI = function newExchangeAPI(logger, BOT) {
let MODULE_NAME = "Exchange API";
let LOG_INFO = true;
let apiClient;
@@ -22,8 +22,7 @@
return thisObject;
function initialize(callBackFunction) {
try {
function initialize() {
exchangeId = bot.exchange.toLowerCase()
let key = process.env.KEY
@@ -41,18 +40,11 @@
verbose: false,
options: options
}
exchange = new exchangeClass(exchangeConstructorParams)
callBackFunction(global.DEFAULT_OK_RESPONSE)
} catch (err) {
logError("initialize -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function getMaxDecimalPositions() {
return 8
return 8
}
async function getTicker(market, callBackFunction) {
@@ -62,13 +54,13 @@
let ticker
if (exchange.has['fetchTicker']) {
ticker = await (exchange.fetchTicker(symbol))
ticker = await (exchange.fetchTicker(symbol))
callBackFunction(global.DEFAULT_OK_RESPONSE, ticker)
} else {
logError("getTicker -> Exchange does not support fetchTicker command.");
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
} catch (err) {
logError("getTicker -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
@@ -83,7 +75,7 @@
let openOrders
if (exchange.has['fetchOpenOrders']) {
openOrders = await(exchange.fetchOpenOrders (symbol))
openOrders = await (exchange.fetchOpenOrders(symbol))
callBackFunction(global.DEFAULT_OK_RESPONSE, openOrders)
} else {
logError("getOpenOrders -> Exchange does not support fetchOpenOrders command.");
@@ -116,7 +108,7 @@
}
}
async function createOrder(market, side, price, cost, amount, callBackFunction) {
async function createOrder(market, side, price, cost, amount, callBackFunction) {
try {
logInfo("createOrder -> Entering function.");
@@ -137,7 +129,7 @@
let order
if (exchange.has['createOrder']) {
order = await(exchange.createOrder(symbol, type, side, amount))
order = await (exchange.createOrder(symbol, type, side, amount))
callBackFunction(global.DEFAULT_OK_RESPONSE, order)
} else {
logError("createOrder -> Exchange does not support createOrder command.");
+52 -48
View File
@@ -22,11 +22,11 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
deleteTextFile: deleteTextFile
}
return thisObject
return thisObject
function getTextFile(filePath, callBackFunction, noRetry, canUsePrevious) {
let currentRetryGetTextFile = 0
let currentRetryGetTextFile = 0
recursiveGetTextFile(filePath, callBackFunction, noRetry, canUsePrevious)
@@ -77,7 +77,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
}
callBackFunction(customResponse)
return
}
}
fileDoesNotExist = true
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Retrying. ')
@@ -106,7 +106,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
if (mustBeJason === false) {
/* In this case there is nothing else to check. */
callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString())
return
return
}
/*
@@ -117,7 +117,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
/* The file was correctly read and could be parsed. */
callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString())
return
return
} catch (err) {
@@ -140,11 +140,11 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> canUsePrevious -> err = ' + err.stack)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
return
}
}
/* Returning the previous file */
callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString())
return
return
}
} else {
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Could read the file, but could not parse it as it is not a valid JSON.')
@@ -153,12 +153,12 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
setTimeout(retry, retryTimeToUse)
return
}
}
}
}
} catch (err) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error writing file -> file = ' + fileLocation)
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error writing file -> err = ' + err.stack)
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error reading file -> file = ' + fileLocation)
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error reading file -> err = ' + err.stack)
retry()
}
@@ -191,16 +191,13 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
}
}
function createTextFile(filePath, fileContent, callBackFunction, keepPrevious) {
function createTextFile(filePath, fileContent, callBackFunction, keepPrevious, noTemp) {
let currentRetryWriteTextFile = 0
recursiveCreateTextFile(filePath, fileContent, callBackFunction, keepPrevious)
function recursiveCreateTextFile(filePath, fileContent, callBackFunction, keepPrevious) {
logger.write(MODULE_NAME, '[INFO] FileStorage -> createTextFile -> Entering Function.')
recursiveCreateTextFile(filePath, fileContent, callBackFunction, keepPrevious, noTemp)
function recursiveCreateTextFile(filePath, fileContent, callBackFunction, keepPrevious, noTemp) {
/* Choose path for either logs or data */
let fileLocation
if (filePath.indexOf("/Logs/") > 0) {
@@ -210,7 +207,6 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
}
try {
logger.write(MODULE_NAME, '[INFO] FileStorage -> createTextFile -> fileLocation: ' + fileLocation)
/* If necesary a folder or folders are created before writing the file to disk. */
@@ -222,7 +218,11 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
Then we delete the original file, if exists, and finally we rename the temporary into the original name.
*/
const fs = require('fs')
fs.writeFile(fileLocation + '.tmp', fileContent, onFileWritenn)
if (noTemp === true) {
fs.writeFile(fileLocation, fileContent, onFileWritenn)
} else {
fs.writeFile(fileLocation + '.tmp', fileContent, onFileWritenn)
}
function onFileWritenn(err) {
let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS
@@ -235,6 +235,10 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
setTimeout(retry, retryTimeToUse)
} else {
if (noTemp === true) {
callBackFunction(global.DEFAULT_OK_RESPONSE)
return
}
if (keepPrevious === true) {
/*
In some cases, we are going to keep a copy of the previous version of the file being written. This will be usefull to recover from crashes
@@ -252,7 +256,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> err = ' + err.stack)
setTimeout(retry, retryTimeToUse)
return
}
}
/* Rename de Original into Previous */
fs.rename(fileLocation, fileLocation + '.Previous.json', onOriginalRenamed)
@@ -266,7 +270,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onOriginalRenamed -> Error renaming original file -> file = ' + fileLocation)
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onOriginalRenamed -> Error renaming original file -> err = ' + err.stack)
setTimeout(retry, retryTimeToUse)
return
return
}
/* Rename de Temp into Original */
@@ -282,13 +286,13 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
callBackFunction(global.DEFAULT_OK_RESPONSE)
}
}
}
}
}
} else {
/* In this case, there is no need to keep a copy of the file being replaced, so we just delete and that's it. */
fs.unlink(fileLocation , onUnlinked)
fs.unlink(fileLocation, onUnlinked)
function onUnlinked(err) {
let code = ''
@@ -296,11 +300,11 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
code = err.code
}
if (code !== '' && code !== 'ENOENT') {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> file = ' + fileLocation )
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> file = ' + fileLocation)
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> err = ' + err.stack)
setTimeout(retry, retryTimeToUse)
return
}
}
/* Rename de Temp into Original */
fs.rename(fileLocation + '.tmp', fileLocation, onTempRenamed)
@@ -406,33 +410,33 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
/* Function to create folders of missing folders at any path. */
function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) {
const sep = '/';
const initDir = path.isAbsolute(targetDir) ? sep : '';
const baseDir = isRelativeToScript ? __dirname : '.';
const sep = '/';
const initDir = path.isAbsolute(targetDir) ? sep : '';
const baseDir = isRelativeToScript ? __dirname : '.';
return targetDir.split(sep).reduce((parentDir, childDir) => {
const curDir = path.resolve(baseDir, parentDir, childDir);
try {
const fs = require('fs')
fs.mkdirSync(curDir);
} catch (err) {
if (err.code === 'EEXIST') { // curDir already exists!
return curDir;
}
return targetDir.split(sep).reduce((parentDir, childDir) => {
const curDir = path.resolve(baseDir, parentDir, childDir);
try {
const fs = require('fs')
fs.mkdirSync(curDir);
} catch (err) {
if (err.code === 'EEXIST') { // curDir already exists!
return curDir;
}
// To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
}
// To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
}
const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
throw err; // Throw if it's just the last created dir.
}
}
const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
throw err; // Throw if it's just the last created dir.
}
}
return curDir;
}, initDir);
return curDir;
}, initDir);
}
function getFileViaHTTP(filePath, callback, callBackFunction) {
@@ -455,7 +459,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
logger.write(MODULE_NAME, "[ERROR] getFileViaHTTP -> onError -> err = " + err.stack);
logger.write(MODULE_NAME, "[ERROR] getFileViaHTTP -> onError -> Failed to fetch file via HTTP. Will retry later. ");
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
})
})
function onResponse(response) {
+760 -122
View File
@@ -1,167 +1,805 @@
exports.newIndicatorBot = function newIndicatorBot(bot, logger, UTILITIES, FILE_STORAGE) {
const FULL_LOG = true;
const LOG_FILE_CONTENT = false;
const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
exports.newIndicatorBot = function newIndicatorBot(bot, parentLogger) {
const MODULE_NAME = "Indicator Bot";
const FULL_LOG = true;
let USER_BOT_MODULE;
let COMMONS_MODULE;
const MULTI_PERIOD_MARKET = require(global.ROOT_DIR + 'MultiPeriodMarket');
const MULTI_PERIOD_DAILY = require(global.ROOT_DIR + 'MultiPeriodDaily');
const FILE_STORAGE = require('./FileStorage.js');
let fileStorage = FILE_STORAGE.newFileStorage(parentLogger);
const DEBUG_MODULE = require(global.ROOT_DIR + 'DebugLog');
let logger; // We need this here in order for the loopHealth function to work and be able to rescue the loop when it gets in trouble.
let nextLoopTimeoutHandle;
let thisObject = {
initialize: initialize,
finalize: finalize,
start: start
run: run
};
let utilities = UTILITIES.newCloudUtilities(logger);
let fileStorage = FILE_STORAGE.newFileStorage(logger);
const COMMONS = require('./Commons.js');
let commons = COMMONS.newCommons(bot, logger, UTILITIES, FILE_STORAGE);
let processConfig;
return thisObject;
function finalize() {
thisObject = undefined
utilities = undefined
fileStorage = undefined
commons = undefined
}
function initialize(callBackFunction) {
function initialize(pProcessConfig, callBackFunction) {
try {
processConfig = pProcessConfig;
logger.fileName = MODULE_NAME;
logger.initialize();
if (bot.definedByUI === true) {
/* The code of the bot is defined at the UI. No need to load a file with the code. */
callBackFunction(global.DEFAULT_OK_RESPONSE);
return
}
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
/* This bot is not ready for taking its code from the UI, then we need to load it from its repo. */
let filePath = bot.dataMine + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.codeName
filePath += "/User.Bot.js"
callBackFunction(global.DEFAULT_OK_RESPONSE);
fileStorage.getTextFile(filePath, onBotDownloaded);
function onBotDownloaded(err, text) {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> err = " + err.message);
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> filePath = " + filePath);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
USER_BOT_MODULE = {}
USER_BOT_MODULE.newUserBot = eval(text); // TODO This needs to be changed function
filePath = bot.dataMine + "/" + "bots" + "/" + bot.repo;
filePath += "/Commons.js"
fileStorage.getTextFile(filePath, onCommonsDownloaded);
function onCommonsDownloaded(err, text) {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
parentLogger.write(MODULE_NAME, "[WARN] initialize -> onBotDownloaded -> onCommonsDownloaded -> Commons not found: " + err.code || err.message);
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
COMMONS_MODULE = {}
COMMONS_MODULE.newCommons = eval(text); // TODO This needs to be changed function
callBackFunction(global.DEFAULT_OK_RESPONSE);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function start(dataFiles, timeFrame, timeFrameLabel, currentDay, interExecutionMemory, callBackFunction) {
function run(callBackFunction) {
try {
let fixedTimeLoopIntervalHandle;
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
/* Errors sent to the UI */
bot.processError = processError
let products = {}
let mainDependency = {}
let processingDailyFiles
/* Heartbeats sent to the UI */
bot.processHeartBeat = processHeartBeat
if (currentDay !== undefined) {
processingDailyFiles = true
if (bot.runAtFixedInterval === true) {
fixedTimeLoopIntervalHandle = setInterval(loop, bot.fixedInterval);
} else {
processingDailyFiles = false
loop();
}
/* The first phase here is about checking that we have everything we need at the definition level. */
let dataDependencies = bot.processNode.referenceParent.processDependencies.dataDependencies
if (commons.validateDataDependencies(dataDependencies, callBackFunction) !== true) { return }
function loop() {
try {
function pad(str, max) {
str = str.toString();
return str.length < max ? pad(" " + str, max) : str;
}
let outputDatasets = bot.processNode.referenceParent.processOutput.outputDatasets
if (commons.validateOutputDatasets(outputDatasets, callBackFunction) !== true) { return }
/* For each loop we want to create a new log file. */
if (logger !== undefined) {
logger.finalize()
}
logger = DEBUG_MODULE.newDebugLog();
global.LOGGER_MAP.set(MODULE_NAME, logger)
logger.bot = bot;
logger.initialize();
/* The second phase is about transforming the inputs into a format that can be used to apply the user defined code. */
commons.inflateDatafiles(dataFiles, dataDependencies, products, mainDependency, timeFrame)
bot.loopCounter++;
bot.loopStartTime = new Date().valueOf();
/* During the third phase, we need to generate the data of the different products this process produces an output */
for (let i = 0; i < outputDatasets.length; i++) {
/* We tell the UI that we are running. */
processHeartBeat()
let outputDatasetNode = outputDatasets[i]
let jsonData // Just build data as Json objects
let outputData // Data built as a result of applying user defined code and formulas at the Data Building Procedure
let singularVariableName // Name of the variable for this product
let recordDefinition // Record as defined by the user at the UI
let fileContent // Here we store the contents of the new data built just before writing it to a file.
let resultsWithIrregularPeriods // A product will have irregular periods when the User Code inserts new result records at will, in contrast with normal procedure where the platform insert one record per loop execution.
/* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */
const UTILITIES = require(global.ROOT_DIR + 'CloudUtilities');
const STATUS_REPORT = require(global.ROOT_DIR + 'StatusReport');
const STATUS_DEPENDENCIES = require(global.ROOT_DIR + 'StatusDependencies');
const DATA_DEPENDENCIES = require(global.ROOT_DIR + 'DataDependencies');
const DATA_SET = require(global.ROOT_DIR + 'DataSet');
const PROCESS_EXECUTION_EVENTS = require(global.ROOT_DIR + 'ProcessExecutionEvents');
const PROCESS_OUTPUT = require(global.ROOT_DIR + 'ProcessOutput');
/*
For each outputDatasetNode in our process output, we will build the information based on our input products.
*/
/* We define the datetime for the process that we are running now. This will be the official processing time for both the infraestructure and the bot. */
bot.processDatetime = new Date(); // This will be considered the process date and time, so as to have it consistenly all over the execution.
recordDefinition = outputDatasetNode.referenceParent.parentNode.record
singularVariableName = outputDatasetNode.referenceParent.parentNode.code.singularVariableName
/* High level log entry */
console.log(new Date().toISOString() + " " + pad(bot.exchange, 20) + " " + pad(bot.market.baseAsset + '/' + bot.market.quotedAsset, 10) + " " + pad(bot.codeName, 30) + " " + pad(bot.process, 30)
+ " Main Loop # " + pad(Number(bot.loopCounter), 8))
/* Check Irregular Periods */
/* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */
let processExecutionEvents
let userBot;
let processFramework;
let statusDependencies;
let dataDependencies;
if (outputDatasetNode.referenceParent.parentNode.dataBuilding.loop.javascriptCode !== undefined) {
if (outputDatasetNode.referenceParent.parentNode.dataBuilding.loop.javascriptCode.code.indexOf('results.push') >= 0) {
resultsWithIrregularPeriods = true
let nextWaitTime;
initializeProcessExecutionEvents();
function initializeProcessExecutionEvents() {
try {
processExecutionEvents = PROCESS_EXECUTION_EVENTS.newProcessExecutionEvents(bot, logger)
processExecutionEvents.initialize(onInizialized);
function onInizialized(err) {
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Execution finished well.");
startProcessExecutionEvents()
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[WARN] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Operation Failed. Aborting the process.");
global.unexpectedError = err.message
processStopped()
return
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeProcessExecutionEvents -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
function startProcessExecutionEvents() {
try {
processExecutionEvents.start(onStarted);
function onStarted(err) {
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessExecutionEvents -> onStarted -> Execution finished well.");
if (global.STOP_TASK_GRACEFULLY === true) {
loopControl()
return
}
initializeStatusDependencies();
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessExecutionEvents -> onStarted -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Operation Failed. Aborting the process.");
global.unexpectedError = err.message
processStopped()
return
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Unhandled err.result received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessExecutionEvents -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
function initializeStatusDependencies() {
try {
statusDependencies = STATUS_DEPENDENCIES.newStatusDependencies(bot, logger, STATUS_REPORT, UTILITIES, PROCESS_OUTPUT);
statusDependencies.initialize(onInizialized);
function onInizialized(err) {
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeStatusDependencies -> onInizialized -> Execution finished well.");
initializeDataDependencies();
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[WARN] run -> loop -> initializeStatusDependencies -> onInizialized -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Operation Failed. Aborting the process.");
global.unexpectedError = err.message
processStopped()
return
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeStatusDependencies -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
function initializeDataDependencies() {
try {
dataDependencies = DATA_DEPENDENCIES.newDataDependencies(bot, logger, DATA_SET);
dataDependencies.initialize(onInizialized);
function onInizialized(err) {
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
/* If the process is configured to run inside a framework, we continue there, otherwise we run the bot directly. */
if (processConfig.framework === undefined) {
initializeUserBot();
return;
}
switch (processConfig.framework.name) {
case 'Multi-Period-Market': {
processFramework = MULTI_PERIOD_MARKET.newMultiPeriodMarket(bot, logger, UTILITIES, FILE_STORAGE);
intitializeProcessFramework();
break;
}
case 'Multi-Period-Daily': {
processFramework = MULTI_PERIOD_DAILY.newMultiPeriodDaily(bot, logger, UTILITIES, FILE_STORAGE);
intitializeProcessFramework();
break;
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework not Supported.");
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework Name = " + processConfig.framework.name);
global.unexpectedError = err.message
processStopped()
return
}
}
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[WARN] run -> loop -> initializeDataDependencies -> onInizialized -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
processStopped()
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Operation Failed. Aborting the process.");
global.unexpectedError = err.message
processStopped()
return
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
function initializeUserBot() {
try {
usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, FILE_STORAGE);
usertBot.initialize(statusDependencies, onInizialized);
function onInizialized(err) {
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeUserBot -> onInizialized -> Execution finished well.");
startUserBot();
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[WARN] run -> loop -> initializeUserBot -> onInizialized -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeUserBot -> onInizialized -> Operation Failed. Aborting the process.");
global.unexpectedError = err.message
processStopped()
return
}
case global.CUSTOM_OK_RESPONSE.result: {
switch (err.message) {
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeUserBot -> onInizialized > Unhandled custom response received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeUserBot -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeUserBot -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeUserBot -> onInizialized -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeUserBot -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
function startUserBot() {
try {
usertBot.start(onFinished);
function onFinished(err) {
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> startUserBot -> onFinished -> Execution finished well.");
finishProcessExecutionEvents()
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[WARN] run -> loop -> startUserBot -> onFinished -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startUserBot -> onFinished -> Operation Failed. Aborting the process.");
global.unexpectedError = err.message
processStopped()
return
}
case global.CUSTOM_OK_RESPONSE.result: {
switch (err.message) {
case "Dependency does not exist.": {
logger.write(MODULE_NAME, "[WARN] run -> loop -> startUserBot -> onFinished -> Dependency does not exist. This Loop will go to sleep.");
nextWaitTime = 'Sleep';
loopControl(nextWaitTime);
return;
}
case "Dependency not ready.": {
logger.write(MODULE_NAME, "[WARN] run -> loop -> startUserBot -> onFinished -> Dependency not ready. Will Retry Later.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startUserBot -> onFinished -> Unhandled custom response received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startUserBot -> onFinished -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startUserBot -> onFinished -> Unhandled err.result received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startUserBot -> onFinished -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startUserBot -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
function intitializeProcessFramework() {
try {
processFramework.initialize(processConfig, statusDependencies, dataDependencies, onInizialized);
function onInizialized(err) {
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeProcessFramework -> onInizialized -> Execution finished well.");
startProcessFramework();
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[WARN] run -> loop -> intitializeProcessFramework -> onInizialized -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Operation Failed. Aborting the process.");
global.unexpectedError = err.message
processStopped()
return
}
case global.CUSTOM_OK_RESPONSE.result: {
switch (err.message) {
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized > Unhandled custom response received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
function startProcessFramework() {
try {
processFramework.start(onFinished);
function onFinished(err) {
try {
processFramework.finalize()
processFramework = undefined
dataDependencies.finalize()
dataDependencies = undefined
statusDependencies.finalize()
statusDependencies = undefined
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> onFinished -> Execution finished well.");
finishProcessExecutionEvents()
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Operation Failed. Aborting the process.");
global.unexpectedError = err.message
processStopped()
return
}
case global.CUSTOM_OK_RESPONSE.result: {
switch (err.message) {
case "Dependency does not exist.": {
logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency does not exist. This Loop will go to sleep.");
nextWaitTime = 'Sleep';
loopControl(nextWaitTime);
return;
}
case "Dependency not ready.": {
logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency not ready. This Loop will go to sleep.");
nextWaitTime = 'Sleep';
loopControl(nextWaitTime);
return;
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled custom response received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
function finishProcessExecutionEvents() {
try {
processExecutionEvents.finish(onFinished);
function onFinished(err) {
try {
processExecutionEvents.finalize()
processExecutionEvents = undefined
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> finishProcessExecutionEvents -> onFinished -> Execution finished well.");
nextWaitTime = 'Normal';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[WARN] run -> loop -> finishProcessExecutionEvents -> onFinished -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Operation Failed. Aborting the process.");
global.unexpectedError = err.message
processStopped()
return
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Unhandled err.result received. -> err = " + err.message);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> finishProcessExecutionEvents -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
function loopControl(nextWaitTime) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> nextWaitTime = " + nextWaitTime); }
/* We show we reached the end of the loop. */
processHeartBeat()
/* Here we check if we must stop the loop gracefully. */
shallWeStop(onStop, onContinue);
function onStop() {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> onStop -> Stopping the Loop Gracefully. See you next time!"); }
processStopped()
return;
}
function onContinue() {
/* Indicator bots are going to be executed after a configured period of time after the last execution ended. This is to avoid overlapping executions. */
switch (nextWaitTime) {
case 'Normal': {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.normalWaitTime / 1000) + " seconds."); }
nextLoopTimeoutHandle = setTimeout(loop, processConfig.normalWaitTime);
processHeartBeat(undefined, undefined, "Waiting " + processConfig.normalWaitTime / 1000 + " seconds for next execution.")
if (global.WRITE_LOGS_TO_FILES === 'true') {
logger.persist();
}
}
break;
case 'Retry': {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.retryWaitTime / 1000) + " seconds."); }
nextLoopTimeoutHandle = setTimeout(loop, processConfig.retryWaitTime);
processHeartBeat(undefined, undefined, "Trying to recover from some problem. Waiting " + processConfig.retryWaitTime / 1000 + " seconds for next execution.")
logger.persist();
}
break;
case 'Sleep': {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.sleepWaitTime / 60000) + " minutes."); }
nextLoopTimeoutHandle = setTimeout(loop, processConfig.sleepWaitTime);
processHeartBeat(undefined, undefined, "Waiting " + processConfig.sleepWaitTime / 60000 + " minutes for next execution.")
logger.persist();
}
break;
case 'Coma': {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.comaWaitTime / 3600000) + " hours."); }
nextLoopTimeoutHandle = setTimeout(loop, processConfig.comaWaitTime);
processHeartBeat(undefined, undefined, "Waiting " + processConfig.comaWaitTime / 3600000 + " hours for next execution.")
logger.persist();
}
break;
}
}
}
function shallWeStop(stopCallBack, continueCallBack) {
try {
/* IMPORTANT: This function is exactly the same on the 3 modules. */
if (!global.STOP_TASK_GRACEFULLY) {
continueCallBack();
} else {
stopCallBack();
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
} catch (err) {
parentLogger.write(MODULE_NAME, "[ERROR] run -> loop -> err = " + err.stack);
global.unexpectedError = err.message
processStopped()
return
}
}
function processHeartBeat(processingDate, percentage, status) {
let event = {
seconds: (new Date()).getSeconds(),
processingDate: processingDate,
percentage: percentage,
status: status
}
global.EVENT_SERVER_CLIENT.raiseEvent(bot.processKey, 'Heartbeat', event)
}
function processError(node, errorMessage) {
let event
if (node !== undefined) {
event = {
nodeName: node.name,
nodeType: node.type,
nodeId: node.id,
errorMessage: errorMessage
}
} else {
event = {
errorMessage: errorMessage
}
}
global.EVENT_SERVER_CLIENT.raiseEvent(bot.processKey, 'Error', event)
}
/* Build the data */
jsonData = commons.dataBuildingProcedure(
products,
mainDependency,
recordDefinition,
outputDatasetNode.referenceParent.parentNode.dataBuilding,
singularVariableName,
outputDatasetNode.referenceParent.parentNode.code.codeName,
timeFrame,
timeFrameLabel,
resultsWithIrregularPeriods,
interExecutionMemory,
processingDailyFiles,
currentDay
)
/* Add the calculated properties */
if (outputDatasetNode.referenceParent.parentNode.calculations !== undefined) {
outputData = commons.calculationsProcedure(jsonData, recordDefinition, outputDatasetNode.referenceParent.parentNode.calculations, singularVariableName, timeFrame)
function processStopped() {
if (global.unexpectedError !== undefined) {
processError(undefined, "An unexpected error caused the Process to stop.")
} else {
outputData = jsonData
global.EVENT_SERVER_CLIENT.raiseEvent(bot.processKey, 'Stopped')
}
products[outputDatasetNode.referenceParent.parentNode.code.pluralVariableName] = outputData
}
/*At the fourth and last phase, we will save the new information generated into files corresponding to each output outputDatasetNode.*/
let totalFilesWritten = 0
for (let i = 0; i < outputDatasets.length; i++) {
let outputDatasetNode = outputDatasets[i]
let outputData = products[outputDatasetNode.referenceParent.parentNode.code.pluralVariableName]
let resultsWithIrregularPeriods // A product will have irregular periods when the User Code inserts new result records at will, in contrast with normal procedure where the platform insert one record per loop execution.
let contextSummary = {}
/* Check Irregular Periods */
if (outputDatasetNode.referenceParent.parentNode.dataBuilding.loop.javascriptCode.code.indexOf('results.push') >= 0) {
resultsWithIrregularPeriods = true
}
/* Simplifying the access to basic info */
contextSummary.dataset = outputDatasetNode.referenceParent.code.codeName
contextSummary.product = outputDatasetNode.referenceParent.parentNode.code.codeName
contextSummary.bot = outputDatasetNode.referenceParent.parentNode.parentNode.code.codeName
contextSummary.dataMine = outputDatasetNode.referenceParent.parentNode.parentNode.parentNode.code.codeName
/* This stuff is still hardcoded and unresolved. */
contextSummary.botVersion = {
"major": 1,
"minor": 0
}
contextSummary.dataSetVersion = "dataSet.V1"
let fileContent = commons.generateFileContent(outputData, outputDatasetNode.referenceParent.parentNode.record, resultsWithIrregularPeriods, processingDailyFiles, currentDay, callBackFunction)
commons.writeFile(contextSummary, fileContent, anotherFileWritten, processingDailyFiles, timeFrameLabel, currentDay, callBackFunction)
}
function anotherFileWritten() {
totalFilesWritten++
if (totalFilesWritten === outputDatasets.length) {
callBackFunction(global.DEFAULT_OK_RESPONSE);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
if (global.unexpectedError !== undefined) {
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
} else {
callBackFunction(global.DEFAULT_OK_RESPONSE)
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
} catch (err) {
parentLogger.write(MODULE_NAME, "[ERROR] run -> err = " + err.stack);
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
File diff suppressed because it is too large. Load diff
+157
View File
@@ -0,0 +1,157 @@
exports.newIndicatorOutput = function newIndicatorOutput(bot, logger, UTILITIES, FILE_STORAGE) {
const FULL_LOG = true;
const MODULE_NAME = "Indicator Bot";
let thisObject = {
initialize: initialize,
finalize: finalize,
start: start
};
let utilities = UTILITIES.newCloudUtilities(logger);
let fileStorage = FILE_STORAGE.newFileStorage(logger);
const COMMONS = require('./Commons.js');
let commons = COMMONS.newCommons(bot, logger, UTILITIES, FILE_STORAGE);
return thisObject;
function finalize() {
thisObject = undefined
utilities = undefined
fileStorage = undefined
commons = undefined
}
function initialize(callBackFunction) {
try {
logger.fileName = MODULE_NAME;
logger.initialize();
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
callBackFunction(global.DEFAULT_OK_RESPONSE);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function start(dataFiles, timeFrame, timeFrameLabel, currentDay, interExecutionMemory, callBackFunction) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
let products = {}
let mainDependency = {}
let processingDailyFiles
if (currentDay !== undefined) {
processingDailyFiles = true
} else {
processingDailyFiles = false
}
/* The first phase here is about checking that we have everything we need at the definition level. */
let dataDependencies = bot.processNode.referenceParent.processDependencies.dataDependencies
if (commons.validateDataDependencies(dataDependencies, callBackFunction) !== true) { return }
let outputDatasets = bot.processNode.referenceParent.processOutput.outputDatasets
if (commons.validateOutputDatasets(outputDatasets, callBackFunction) !== true) { return }
/* The second phase is about transforming the inputs into a format that can be used to apply the user defined code. */
commons.inflateDatafiles(dataFiles, dataDependencies, products, mainDependency, timeFrame)
/* During the third phase, we need to generate the data of the different products this process produces an output */
for (let i = 0; i < outputDatasets.length; i++) {
let outputDatasetNode = outputDatasets[i]
let jsonData // Just build data as Json objects
let outputData // Data built as a result of applying user defined code and formulas at the Data Building Procedure
let singularVariableName // Name of the variable for this product
let recordDefinition // Record as defined by the user at the UI
let fileContent // Here we store the contents of the new data built just before writing it to a file.
let resultsWithIrregularPeriods // A product will have irregular periods when the User Code inserts new result records at will, in contrast with normal procedure where the platform insert one record per loop execution.
/*
For each outputDatasetNode in our process output, we will build the information based on our input products.
*/
recordDefinition = outputDatasetNode.referenceParent.parentNode.record
singularVariableName = outputDatasetNode.referenceParent.parentNode.config.singularVariableName
/* Check Irregular Periods */
if (outputDatasetNode.referenceParent.parentNode.dataBuilding.loop.javascriptCode !== undefined) {
if (outputDatasetNode.referenceParent.parentNode.dataBuilding.loop.javascriptCode.code.indexOf('results.push') >= 0) {
resultsWithIrregularPeriods = true
}
}
/* Build the data */
jsonData = commons.dataBuildingProcedure(
products,
mainDependency,
recordDefinition,
outputDatasetNode.referenceParent.parentNode.dataBuilding,
singularVariableName,
outputDatasetNode.referenceParent.parentNode.config.codeName,
timeFrame,
timeFrameLabel,
resultsWithIrregularPeriods,
interExecutionMemory,
processingDailyFiles,
currentDay
)
/* Add the calculated properties */
if (outputDatasetNode.referenceParent.parentNode.calculations !== undefined) {
outputData = commons.calculationsProcedure(jsonData, recordDefinition, outputDatasetNode.referenceParent.parentNode.calculations, singularVariableName, timeFrame)
} else {
outputData = jsonData
}
products[outputDatasetNode.referenceParent.parentNode.config.pluralVariableName] = outputData
}
/*At the fourth and last phase, we will save the new information generated into files corresponding to each output outputDatasetNode.*/
let totalFilesWritten = 0
for (let i = 0; i < outputDatasets.length; i++) {
let outputDatasetNode = outputDatasets[i]
let outputData = products[outputDatasetNode.referenceParent.parentNode.config.pluralVariableName]
let resultsWithIrregularPeriods // A product will have irregular periods when the User Code inserts new result records at will, in contrast with normal procedure where the platform insert one record per loop execution.
let contextSummary = {}
/* Check Irregular Periods */
if (outputDatasetNode.referenceParent.parentNode.dataBuilding.loop.javascriptCode.code.indexOf('results.push') >= 0) {
resultsWithIrregularPeriods = true
}
/* Simplifying the access to basic info */
contextSummary.dataset = outputDatasetNode.referenceParent.config.codeName
contextSummary.product = outputDatasetNode.referenceParent.parentNode.config.codeName
contextSummary.bot = outputDatasetNode.referenceParent.parentNode.parentNode.config.codeName
contextSummary.dataMine = outputDatasetNode.referenceParent.parentNode.parentNode.parentNode.config.codeName
let fileContent = commons.generateFileContent(outputData, outputDatasetNode.referenceParent.parentNode.record, resultsWithIrregularPeriods, processingDailyFiles, currentDay, callBackFunction)
commons.writeFile(contextSummary, fileContent, anotherFileWritten, processingDailyFiles, timeFrameLabel, currentDay, callBackFunction)
}
function anotherFileWritten() {
totalFilesWritten++
if (totalFilesWritten === outputDatasets.length) {
callBackFunction(global.DEFAULT_OK_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
};
@@ -0,0 +1,61 @@
exports.newAnnouncements = function newAnnouncements(bot, logger) {
const MODULE_NAME = 'Announcements'
let thisObject = {
makeAnnoucements: makeAnnoucements,
initialize: initialize,
finalize: finalize
}
let tradingSystem
let tradingEngine
return thisObject
function initialize() {
tradingSystem = bot.simulationState.tradingSystem
tradingEngine = bot.simulationState.tradingEngine
}
function finalize() {
tradingSystem = undefined
tradingEngine = undefined
bot.SESSION.messagesSent = undefined
}
function makeAnnoucements(node) {
if (node.announcements !== undefined) {
for (let i = 0; i < node.announcements.length; i++) {
let announcement = node.announcements[i]
let canAnnounce = true
if (announcement.announcementCondition !== undefined) {
let conditionValue
try {
conditionValue = eval(announcement.announcementCondition.code)
} catch (err) {
tradingSystem.errors.push([announcement.announcementCondition.id, err.message])
}
if (conditionValue !== true) { canAnnounce = false }
}
if (canAnnounce === true) {
let text = announcement.config.text
if (announcement.formula !== undefined) {
try {
text = eval(announcement.formula.code)
} catch (err) {
tradingSystem.errors.push([announcement.formula.id, err.message])
}
}
if (bot.SESSION.socialBots !== undefined) {
bot.SESSION.socialBots.announce(text)
tradingSystem.announcements.push([announcement.id, text])
} else {
tradingSystem.errors.push([announcement.id, 'Could not announce because session does not have Social Bots.'])
}
}
}
}
}
}
+336
View File
@@ -0,0 +1,336 @@
exports.newSnapshots = function newSnapshots(bot, logger) {
/*
This module encapsulates the snapshots functionality.
*/
const MODULE_NAME = 'Snapshots'
let thisObject = {
reset: reset,
strategyEntry: strategyEntry,
strategyExit: strategyExit,
positionEntry: positionEntry,
positionExit: positionExit,
addCodeToSnapshot: addCodeToSnapshot,
initialize: initialize,
finalize: finalize
}
let tradingEngine
let tradingSystem
let sessionParameters
const SNAPSHOTS_FOLDER_NAME = 'Snapshots'
/* Snapshots of Strategies and Positions */
let snapshots = {
headers: [],
strategies: [],
positions: []
}
let positionKeys = new Map() // This is to prevent adding the same indicator / variable to the output collection.
let strategyKeys = new Map()
let createHeaders = true // This is going to be true only once
let createCloseHeaders = true // This is going to be true only once
let closeValues
let strategyValues
let addToStrategyValues
let positionValues
let addToPositionValues
let chart
return thisObject
function initialize() {
tradingEngine = bot.simulationState.tradingEngine
tradingSystem = bot.simulationState.tradingSystem
sessionParameters = bot.SESSION.parameters
}
function finalize() {
writeSnapshotFiles()
tradingEngine = undefined
tradingSystem = undefined
sessionParameters = undefined
positionKeys = undefined
strategyKeys = undefined
chart = undefined
}
function reset(pChart) {
/* This function helps reset data structures at every cycle of the simulation loop/=. */
chart = pChart // We need chat to be a local object accessible from conditions and formulas.
}
function strategyEntry() {
/*
We will record here a snapshot of all values used in conditions and formulas within the Trading System.
If the strategy exists with a trade, this information will be added to the snapshots file.
*/
strategyKeys = new Map()
strategyValues = []
addToStrategyValues = true
evalNode(tradingSystem)
/* Turn off this */
createHeaders = false
addToStrategyValues = false
}
function strategyExit() {
getResults(tradingEngine.current.strategy.begin.value, tradingEngine.current.strategy.end.value)
let valuesArray = closeValues.concat(strategyValues)
snapshots.strategies.push(valuesArray)
}
function positionEntry() {
positionKeys = new Map()
positionValues = []
addToPositionValues = true
evalNode(tradingSystem)
/* Turn off this */
createHeaders = false
addToPositionValues = false
}
function positionExit() {
getResults(tradingEngine.current.position.begin.value, tradingEngine.current.position.end.value)
let valuesArray = closeValues.concat(positionValues)
snapshots.positions.push(valuesArray)
}
function evalNode(node) {
if (node === undefined) { return }
/* Here we check if there is a codition to be evaluated */
if (node.type === 'Condition') {
/* We will eval this condition */
evalCondition(node)
}
/* Here we check if there is a formula to be evaluated */
if (node.type === 'Formula') {
if (node.code !== undefined) {
/* We will eval this formula */
evalFormula(node)
}
}
/* Now we go down through all this node children */
let nodeDefinition = bot.APP_SCHEMA_MAP.get(node.type)
if (nodeDefinition === undefined) { return }
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (node[property.name] !== undefined) {
evalNode(node[property.name])
}
previousPropertyName = property.name
}
break
}
case 'array': {
if (node[property.name] !== undefined) {
let nodePropertyArray = node[property.name]
for (let m = 0; m < nodePropertyArray.length; m++) {
evalNode(nodePropertyArray[m])
}
}
break
}
}
}
}
}
function evalCondition(node) {
/*
The code can be at the condition node if it was done with the Conditions Editor, or it can also be
at a Javascript Code node. If there is a Javascript object we will give it preference and take the code
from there. Otherwise we will take the code from the Condition node.
*/
let nodeWithCode = node
if (node.javascriptCode !== undefined) {
if (node.javascriptCode.code !== undefined) {
nodeWithCode = node.javascriptCode
}
}
addCodeToSnapshot(nodeWithCode)
}
function evalFormula(node) {
let nodeWithCode = node
addCodeToSnapshot(nodeWithCode)
}
function addCodeToSnapshot(nodeWithCode) {
if (nodeWithCode === undefined) { return }
if (nodeWithCode.code === undefined) { return }
try {
let instructionsArray = nodeWithCode.code.split(' ')
for (let i = 0; i < instructionsArray.length; i++) {
let instruction = instructionsArray[i]
instruction = instruction.replace('(', '')
instruction = instruction.replace(')', '')
instruction = instruction.replace(/</g, '')
instruction = instruction.replace(/>/g, '')
instruction = instruction.replace(/<=/g, '')
instruction = instruction.replace(/>=/g, '')
instruction = instruction.replace(/!=/g, '')
instruction = instruction.replace(/!==/g, '')
instruction = instruction.replace(/==/g, '')
instruction = instruction.replace(/===/g, '')
instruction = instruction.replace(/{/g, '')
instruction = instruction.replace(/}/g, '')
if (instruction.indexOf('chart') >= 0) {
let parts = instruction.split('.')
let timeFrame = parts[1]
let product = parts[2]
let property
checkPrevious(3)
function checkPrevious(index) {
property = parts[index]
if (property === 'previous') {
product = product + '.previous'
checkPrevious(index + 1)
}
}
// Example: chart.at01hs.popularSMA.sma200 - chart.at01hs.popularSMA.sma100 < 10
if (timeFrame !== 'atAnyTimeFrame') {
timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7)
}
let key = timeFrame + '-' + product + '-' + property
let existingKey
if (addToStrategyValues === true) {
addValues(strategyKeys, strategyValues)
}
if (addToPositionValues === true) {
addValues(positionKeys, positionValues)
}
function addValues(keys, values) {
existingKey = keys.get(key)
if (existingKey === undefined) { // means that at the current loop this property of this product was not used before.
keys.set(key, key)
if (createHeaders === true) {
snapshots.headers.push(key)
}
let value = eval(instruction)
values.push(value)
}
}
}
}
} catch (err) {
tradingSystem.errors.push(nodeWithCode.id, err.message)
logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> nodeWithCode.code = ' + nodeWithCode.code)
logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> err = ' + err.stack)
}
}
function getResults(openDatetime, closeDatetime) {
let closeHeaders = ['Trade Number', 'Open Datetime', 'Close Datetime', 'Strategy Name', 'Trigger On Situation', 'Take Position Situation', 'Result', 'ROI', 'Exit Type']
closeValues = [
tradingEngine.episode.episodeCounters.positions.value, // Position Number
(new Date(openDatetime)).toISOString(), // Open Datetime
(new Date(closeDatetime)).toISOString(), // Open Datetime
tradingEngine.current.strategy.strategyName.value, // Strategy Name
tradingEngine.current.strategy.situationName.value, // Trigger On Situation
tradingEngine.current.position.situationName.value, // Take Position Situation
tradingEngine.current.position.positionStatistics.hitFail.value, // Result
tradingEngine.current.position.positionStatistics.ROI.value, // ROI
tradingEngine.current.position.exitType.value // Exit Type
]
if (createCloseHeaders === true) {
snapshots.headers = closeHeaders.concat(JSON.parse(JSON.stringify(snapshots.headers)))
createCloseHeaders = false
}
}
function writeSnapshotFiles() {
if (sessionParameters.snapshots !== undefined) {
if (sessionParameters.snapshots.config.strategy === true) {
writeSnapshotFile(snapshots.strategies, 'Strategies')
}
}
if (sessionParameters.snapshots !== undefined) {
if (sessionParameters.snapshots.config.strategy === true) {
writeSnapshotFile(snapshots.positions, 'Positions')
}
}
}
function writeSnapshotFile(snapshotArray, pFileName) {
try {
const FILE_STORAGE = require('../FileStorage.js');
let fileStorage = FILE_STORAGE.newFileStorage(logger);
let fileContent = "";
let separator = "\r\n";
parseRecord(snapshots.headers)
for (let i = 0; i < snapshotArray.length; i++) {
let record = snapshotArray[i];
parseRecord(record)
}
function parseRecord(record) {
for (let j = 0; j < record.length; j++) {
let property = record[j]
fileContent = fileContent + '' + property
if (j !== record.length - 1) {
fileContent = fileContent + ","
}
}
fileContent = fileContent + separator
}
fileContent = "" + fileContent + "";
let fileName = pFileName + '.csv';
let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SNAPSHOTS_FOLDER_NAME;
filePath += '/' + fileName
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
function onFileCreated(err) {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] writeSnapshotFile -> onFileCreated -> err = " + err.stack);
logger.write(MODULE_NAME, "[ERROR] writeSnapshotFile -> onFileCreated -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] writeSnapshotFile -> onFileCreated -> market = " + market.baseAsset + "_" + market.quotedAsset);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] writeSnapshotFile -> err = " + err.stack);
}
}
}
@@ -0,0 +1,168 @@
exports.newTradingEngine = function newTradingEngine(bot, logger) {
/*
We call the Trading Engine to the data structure that is needed in order to exevute the
trading protocol with the specific rules defined at the Trading System.
*/
const MODULE_NAME = 'Trading Engine'
let thisObject = {
cloneValues: cloneValues,
setCurrentCandle: setCurrentCandle,
updateEpisodeCountersAndStatistics: updateEpisodeCountersAndStatistics,
updateDistanceToEventsCounters: updateDistanceToEventsCounters,
initialize: initialize,
finalize: finalize
}
let tradingEngine
let sessionParameters
return thisObject
function initialize() {
/* Here we will go through all the nodes in the Trading Engine hiriarchy and apply the initial value to the value property when needed */
tradingEngine = bot.simulationState.tradingEngine
sessionParameters = bot.SESSION.parameters
if (bot.FIRST_EXECUTION === true) {
initializeNode(tradingEngine)
tradingEngine.current.balance.baseAsset.value = sessionParameters.sessionBaseAsset.config.initialBalance
tradingEngine.current.balance.quotedAsset.value = sessionParameters.sessionQuotedAsset.config.initialBalance
}
}
function finalize() {
tradingEngine = undefined
sessionParameters = undefined
}
function setCurrentCandle(candle) {
cloneValues(tradingEngine.current.candle, tradingEngine.previous.candle)
tradingEngine.current.candle.begin.value = candle.begin
tradingEngine.current.candle.end.value = candle.end
tradingEngine.current.candle.open.value = candle.open
tradingEngine.current.candle.close.value = candle.close
tradingEngine.current.candle.min.value = candle.min
tradingEngine.current.candle.max.value = candle.max
}
function cloneValues(originNode, destinationNode) {
if (originNode === undefined) { return }
if (destinationNode === undefined) { return }
/* Here copy the node value */
destinationNode.value = originNode.value
/* Now we go down through all the children of the origin node, assuming the destination node has the same children structure*/
let nodeDefinition = bot.APP_SCHEMA_MAP.get(originNode.type)
if (nodeDefinition === undefined) { return }
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (originNode[property.name] !== undefined && destinationNode[property.name] !== undefined) {
cloneValues(originNode[property.name], destinationNode[property.name])
}
previousPropertyName = property.name
}
break
}
case 'array': {
if (originNode[property.name] !== undefined && destinationNode[property.name] !== undefined) {
let originNodePropertyArray = originNode[property.name]
let destinationNodePropertyArray = destinationNode[property.name]
for (let m = 0; m < originNodePropertyArray.length; m++) {
cloneValues(originNodePropertyArray[m], destinationNodePropertyArray[m])
}
}
break
}
}
}
}
}
function initializeNode(node) {
if (node === undefined) { return }
/* Here we initialize the node value */
if (node.config !== undefined) {
if (node.config.initialValue !== undefined) {
node.value = node.config.initialValue
}
}
node.initialize = initializeNode // This will allow anyone to initialize this node and its children.
/* Now we go down through all this node children */
let nodeDefinition = bot.APP_SCHEMA_MAP.get(node.type)
if (nodeDefinition === undefined) { return }
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (node[property.name] !== undefined) {
initializeNode(node[property.name])
}
previousPropertyName = property.name
}
break
}
case 'array': {
if (node[property.name] !== undefined) {
let nodePropertyArray = node[property.name]
for (let m = 0; m < nodePropertyArray.length; m++) {
initializeNode(nodePropertyArray[m])
}
}
break
}
}
}
}
}
function updateEpisodeCountersAndStatistics() {
tradingEngine.episode.episodeCounters.periods.value++
tradingEngine.episode.episodeStatistics.days.value = tradingEngine.episode.episodeCounters.periods.value * sessionParameters.timeFrame.config.value / global.ONE_DAY_IN_MILISECONDS
}
function updateDistanceToEventsCounters() {
/* Keeping Distance Counters Up-to-date */
if (
tradingEngine.current.distanceToEvent.triggerOn.value > 0 // with this we avoind counting before the first event happens.
) {
tradingEngine.current.distanceToEvent.triggerOn.value++
}
if (
tradingEngine.current.distanceToEvent.triggerOff.value > 0 // with this we avoind counting before the first event happens.
) {
tradingEngine.current.distanceToEvent.triggerOff.value++
}
if (
tradingEngine.current.distanceToEvent.takePosition.value > 0 // with this we avoind counting before the first event happens.
) {
tradingEngine.current.distanceToEvent.takePosition.value++
}
if (
tradingEngine.current.distanceToEvent.closePosition.value > 0 // with this we avoind counting before the first event happens.
) {
tradingEngine.current.distanceToEvent.closePosition.value++
}
}
}
@@ -0,0 +1,319 @@
exports.newTradingExecution = function newTradingExecution(bot, logger) {
/*
The Trading Execution modules manages the execution of orders against the exchanges.
*/
const MODULE_NAME = 'Trading Execution'
let thisObject = {
takePosition: takePosition,
closePosition: closePosition,
initialize: initialize,
finalize: finalize
}
let tradingEngine
return thisObject
function initialize() {
tradingEngine = bot.simulationState.tradingEngine
}
function finalize() {
tradingEngine = undefined
}
function takePosition() {
/* Check that we are in LIVE MODE */
if (bot.SESSION.type === 'Live Trading Session' || bot.SESSION.type === 'Fordward Testion Session') {
logger.write(MODULE_NAME, '[PERSIST] runSimulation -> loop -> takePositionNow -> Taking a Position in ' + bot.SESSION.type)
logger.write(MODULE_NAME, '[PERSIST] runSimulation -> loop -> takePositionNow -> tradingEngine.current.position.size.value = ' + tradingEngine.current.position.size.value)
logger.write(MODULE_NAME, '[PERSIST] runSimulation -> loop -> takePositionNow -> tradingEngine.current.position.rate.value = ' + tradingEngine.current.position.rate.value)
logger.write(MODULE_NAME, '[PERSIST] runSimulation -> loop -> takePositionNow -> slippageAmount = ' + slippageAmount)
logger.write(MODULE_NAME, '[PERSIST] runSimulation -> loop -> takePositionNow -> tradingEngine.current.position.rate.value = ' + tradingEngine.current.position.rate.value)
/* We see if we need to put the actual order at the exchange. */
if (variable.executionContext !== undefined) {
switch (variable.executionContext.status) {
case 'Without a Position': { // We need to put the order because It was not put yet.
if (strategy.openStage !== undefined) {
if (strategy.openStage.openExecution !== undefined) {
putOpeningOrder()
return
}
}
break
}
case 'Position Closed': { // Waiting for a confirmation that the position was closed.
if (strategy.openStage !== undefined) {
if (strategy.openStage.openExecution !== undefined) {
putOpeningOrder()
return
}
}
break
}
case 'Taking Position': { // Waiting for a confirmation that the position was taken.
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is Taking Position.')
break
}
case 'In a Position': { // This should mean that we already put the order at the exchange.
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is In a Position.')
break
}
}
} else { // The context does not exist so it means we are not in a position.
if (strategy.openStage !== undefined) {
if (strategy.openStage.openExecution !== undefined) {
putOpeningOrder()
return
}
}
}
} else {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Not trading live.')
}
}
function putOpeningOrder() {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Entering function.')
/* We wont take a position unless we are withing the sessionParameters.timeRange.config.initialDatetime and the sessionParameters.timeRange.config.finalDatetime range */
if (sessionParameters.timeRange.config.initialDatetime !== undefined) {
if (candle.end < sessionParameters.timeRange.config.initialDatetime) {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because current candle ends before the start date. -> sessionParameters.timeRange.config.initialDatetime = ' + sessionParameters.timeRange.config.initialDatetime)
takePositionAtSimulation()
return
}
}
/* We wont take a position if we are past the final datetime */
if (sessionParameters.timeRange.config.finalDatetime !== undefined) {
if (candle.begin > sessionParameters.timeRange.config.finalDatetime) {
logger.write(MODULE_NAME, '[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> sessionParameters.timeRange.config.finalDatetime = ' + sessionParameters.timeRange.config.finalDatetime)
takePositionAtSimulation()
return
}
}
/* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */
if (variable.executionContext !== undefined) {
if (variable.executionContext.periods !== undefined) {
if (tradingEngine.episode.episodeCounters.periods.value <= variable.executionContext.periods) {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution.')
takePositionAtSimulation()
return
}
}
}
/* We are not going to place orders based on outdated information. The next filter prevents firing orders when backtesting. */
if (currentDay) {
let today = new Date(Math.trunc((new Date().valueOf()) / global.ONE_DAY_IN_MILISECONDS) * global.ONE_DAY_IN_MILISECONDS)
let processDay = new Date(Math.trunc(currentDay.valueOf() / global.ONE_DAY_IN_MILISECONDS) * global.ONE_DAY_IN_MILISECONDS)
if (today.valueOf() !== processDay.valueOf()) {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because the current candle belongs to the previous day and that is considered simulation and not live trading.')
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> today = ' + today)
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> processDay = ' + processDay)
takePositionAtSimulation()
return
}
}
let orderPrice
let amountA
let amountB
let orderSide
if (bot.sessionAndMarketBaseAssetsAreEqual) {
orderSide = 'sell'
orderPrice = tradingEngine.current.position.rate.value
amountA = tradingEngine.current.position.size.value * orderPrice
amountB = tradingEngine.current.position.size.value
} else {
orderSide = 'buy'
orderPrice = tradingEngine.current.position.rate.value
amountA = tradingEngine.current.position.size.value
amountB = tradingEngine.current.position.size.value / orderPrice
}
variable.executionContext = {
status: 'Taking Position',
periods: tradingEngine.episode.episodeCounters.periods.value
}
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Ready to create order.')
exchangeAPI.createOrder(bot.market, orderSide, orderPrice, amountA, amountB, onOrderCreated)
function onOrderCreated(err, order) {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Entering function.')
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE ')
variable.executionContext = {
status: 'In a Position',
periods: tradingEngine.episode.episodeCounters.periods.value,
amountA: amountA,
amountB: amountB,
orderId: order.id
}
takePositionAtSimulation()
return
}
case global.DEFAULT_FAIL_RESPONSE.result: {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_FAIL_RESPONSE ')
logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Message = ' + err.message)
strategy.openStage.openExecution.error = err.message
afterLoop()
return
}
case global.DEFAULT_RETRY_RESPONSE.result: {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_RETRY_RESPONSE ')
logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Message = ' + err.message)
strategy.openStage.openExecution.error = err.message
afterLoop()
return
}
}
logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Unexpected Response -> Message = ' + err.message)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
return
} catch (err) {
logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> err = ' + err.stack)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
return
}
}
}
function closePosition() {
/* Check that we are in LIVE MODE */
if (bot.SESSION.type === 'Live Trading Session' || bot.SESSION.type === 'Fordward Testion Session') {
/* We see if we need to put the actual order at the exchange. */
if (variable.executionContext !== undefined) {
switch (variable.executionContext.status) {
case 'Without a Position': { // No way to close anything at the exchange.
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Without a Position.')
break
}
case 'In a Position': { // This should mean that we already put the order at the exchange.
if (strategy.closeStage !== undefined) {
if (strategy.closeStage.closeExecution !== undefined) {
putClosingOrder()
return
}
}
break
}
case 'Closing Position': { // Waiting for a confirmation that the position was taken.
if (strategy.closeStage !== undefined) {
if (strategy.closeStage.closeExecution !== undefined) {
putClosingOrder()
return
}
}
break
}
case 'Position Closed': { //
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Position Closed.')
break
}
}
}
}
}
function putClosingOrder() {
/* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */
if (variable.executionContext !== undefined) {
if (variable.executionContext.periods !== undefined) {
if (tradingEngine.episode.episodeCounters.periods.value <= variable.executionContext.periods) {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> Exiting function because this closing was already submited at a previous execution.')
closePositionAtSimulation()
return
}
}
}
let orderPrice
let amountA
let amountB
let orderSide
if (bot.sessionAndMarketBaseAssetsAreEqual) {
orderSide = 'buy'
orderPrice = ticker.last + 100 // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff.
amountA = tradingEngine.current.balance.quotedAsset.value
amountB = tradingEngine.current.balance.quotedAsset.value / orderPrice
} else {
orderSide = 'sell'
orderPrice = ticker.last - 100 // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff.
amountA = tradingEngine.current.balance.baseAsset.value * orderPrice
amountB = tradingEngine.current.balance.baseAsset.value
}
variable.executionContext = {
status: 'Closing Position',
periods: tradingEngine.episode.episodeCounters.periods.value
}
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> About to close position at the exchange.')
exchangeAPI.createOrder(bot.market, orderSide, orderPrice, amountA, amountB, onOrderCreated)
function onOrderCreated(err, order) {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> Entering function.')
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE ')
variable.executionContext = {
status: 'Position Closed',
periods: tradingEngine.episode.episodeCounters.periods.value,
amountA: amountA,
amountB: amountB,
orderId: order.id
}
closePositionAtSimulation()
return
}
case global.DEFAULT_FAIL_RESPONSE.result: {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> DEFAULT_FAIL_RESPONSE ')
/* We will assume that the problem is temporary, and expect that it will work at the next execution. */
strategy.closeStage.closeExecution.error = err.message
afterLoop()
return
}
case global.DEFAULT_RETRY_RESPONSE.result: {
logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_RETRY_RESPONSE ')
strategy.closeStage.closeExecution.error = err.message
afterLoop()
return
}
}
logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> Unexpected Response -> Message = ' + err.message)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
return
} catch (err) {
logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> err = ' + err.stack)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
return
}
}
}
}
@@ -0,0 +1,276 @@
exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FILE_STORAGE) {
/*
This module will load if necesary all the data outputs so that they can be appended with new
records if needed. After running the simulation, it will save all the data outputs.
*/
const FULL_LOG = true
const MODULE_NAME = 'Trading Bot'
let thisObject = {
initialize: initialize,
finalize: finalize,
start: start
}
let utilities = UTILITIES.newCloudUtilities(logger)
let fileStorage = FILE_STORAGE.newFileStorage(logger)
return thisObject
function finalize() {
thisObject = undefined
utilities = undefined
fileStorage = undefined
commons = undefined
}
function initialize(callBackFunction) {
try {
logger.fileName = MODULE_NAME
logger.initialize()
callBackFunction(global.DEFAULT_OK_RESPONSE)
} catch (err) {
logger.write(MODULE_NAME, '[ERROR] initialize -> err = ' + err.stack)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
}
}
function start(chart, timeFrame, timeFrameLabel, currentDay, callBackFunction) {
try {
bot.processingDailyFiles
if (timeFrame > global.dailyFilePeriods[0][0]) {
bot.processingDailyFiles = false
} else {
bot.processingDailyFiles = true
}
/* Preparing everything for the Simulation */
const TRADING_SIMULATION = require('./TradingSimulation.js')
let tradingSimulation = TRADING_SIMULATION.newTradingSimulation(bot, logger, UTILITIES)
let outputDatasets = bot.processNode.referenceParent.processOutput.outputDatasets
let market = bot.market
let totalFilesToBeRead = 0
let totalFilesRead = 0
let totalFilesToBeWritten = 0
let totalFilesWritten = 0
let outputDatasetsMap = new Map()
if (bot.FIRST_EXECUTION === true && bot.RESUME === false) {
/*
Here is where the Trading Engine and Trading Systems received are moved to the simulation state.
*/
bot.simulationState.tradingEngine = bot.TRADING_ENGINE
bot.simulationState.tradingSystem = bot.TRADING_SYSTEM
initializeOutputs()
} else {
readFiles()
}
return
function initializeOutputs() {
if (bot.processingDailyFiles) {
initializeDailyFiles()
} else {
initializeMarketFiles()
}
}
function initializeDailyFiles() {
for (let i = 0; i < outputDatasets.length; i++) {
let outputDatasetNode = outputDatasets[i]
let dataset = outputDatasetNode.referenceParent
if (dataset.config.type === 'Daily Files') {
outputDatasetsMap.set(dataset.parentNode.config.codeName, [])
}
}
runSimulation()
}
function initializeMarketFiles() {
for (let i = 0; i < outputDatasets.length; i++) {
let outputDatasetNode = outputDatasets[i]
let dataset = outputDatasetNode.referenceParent
if (dataset.config.type === 'Market Files') {
outputDatasetsMap.set(dataset.parentNode.config.codeName, [])
}
}
runSimulation()
}
function readFiles() {
/*
This bot have an output of files that it generates. At every call to the bot, it needs to read the previously generated
files in order to later append more information after the execution is over. Here in this function we are going to
read those output files and get them ready for appending content during the simulation.
*/
if (bot.processingDailyFiles) {
readDailyFiles()
} else {
readMarketFiles()
}
}
function readMarketFiles() {
for (let i = 0; i < outputDatasets.length; i++) {
let outputDatasetNode = outputDatasets[i]
let dataset = outputDatasetNode.referenceParent
if (dataset.config.type === 'Market Files') {
let fileName = 'Data.json'
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
}
}
}
function readDailyFiles() {
for (let i = 0; i < outputDatasets.length; i++) {
let outputDatasetNode = outputDatasets[i]
let dataset = outputDatasetNode.referenceParent
if (dataset.config.type === 'Daily Files') {
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let fileName = 'Data.json'
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
}
}
}
function readOutputFile(fileName, filePath, productName) {
totalFilesToBeRead++
filePath += '/' + fileName
fileStorage.getTextFile(filePath, onFileRead, true)
function onFileRead(err, text) {
try {
if (err.message === 'File does not exist.') {
outputDatasetsMap.set(productName, [])
anotherFileRead()
return
}
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> err = ' + err.stack)
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> filePath = ' + filePath)
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset)
callBackFunction(err)
return
}
outputDatasetsMap.set(productName, JSON.parse(text))
anotherFileRead()
} catch (err) {
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> err = ' + err.stack)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
}
}
}
function anotherFileRead() {
totalFilesRead++
if (totalFilesRead === totalFilesToBeRead) {
runSimulation()
}
}
function runSimulation() {
tradingSimulation.runSimulation(
chart,
outputDatasetsMap,
writeFiles,
callBackFunction)
}
function writeFiles() {
/*
The output of files which were appended with information during the simulation execution, now needs to be saved.
*/
if (bot.processingDailyFiles) {
writeDailyFiles()
} else {
writeMarketFiles()
}
}
function writeMarketFiles() {
for (let i = 0; i < outputDatasets.length; i++) {
let outputDatasetNode = outputDatasets[i]
let dataset = outputDatasetNode.referenceParent
if (dataset.config.type === 'Market Files') {
let fileName = 'Data.json'
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
}
}
}
function writeDailyFiles() {
for (let i = 0; i < outputDatasets.length; i++) {
let outputDatasetNode = outputDatasets[i]
let dataset = outputDatasetNode.referenceParent
if (dataset.config.type === 'Daily Files') {
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let fileName = 'Data.json'
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
}
}
}
function writeOutputFile(fileName, filePath, productName) {
totalFilesToBeWritten++
filePath += '/' + fileName
let fileContent = JSON.stringify(outputDatasetsMap.get(productName))
fileStorage.createTextFile(filePath, fileContent, onFileCreated)
function onFileCreated(err) {
try {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> err = ' + err.stack)
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> filePath = ' + filePath)
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset)
callBackFunction(err)
return
}
anotherFileWritten()
} catch (err) {
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> err = ' + err.stack)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
}
}
}
function anotherFileWritten() {
totalFilesWritten++
if (totalFilesWritten === totalFilesToBeWritten) {
callBackFunction(global.DEFAULT_OK_RESPONSE)
}
}
} catch (err) {
logger.write(MODULE_NAME, '[ERROR] start -> err = ' + err.stack)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
}
}
}
Loaded 100 of 123 files, more files were not shown because too many files have changed in this diff. Show more