Beta 6 without Execution
This commit is contained in:
1 parent
4033d4d07f
commit
d40b985f5e
123 files changed
+8114
-12392
No files matched your search
@@ -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 |
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+4
-4
@@ -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;
|
||||
|
||||
+1
-1
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+4
-4
@@ -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;
|
||||
|
||||
+4
-4
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+7
-7
@@ -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 */
|
||||
|
||||
+13
-13
@@ -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 {
|
||||
|
||||
+90
-99
@@ -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 */
|
||||
|
||||
|
||||
+30
-30
@@ -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)
|
||||
|
||||
+12
-12
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
+16
-16
@@ -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 @@
|
||||
{"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
@@ -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 = ","; }
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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.'])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in new issue
Block a user