Trading Engines Data Mine

This commit is contained in:
Luis Fernando Molina committed 2020-03-19 15:04:45 +01:00
1 parent d871f2c4a1
commit 8033226721
31 files changed
+6069 -129

No files matched your search

+5 -1
View File
@@ -1279,7 +1279,7 @@
"addLeftIcons": true,
"level": 1,
"chainAttachesTo": {
"compatibleTypes": "->Exchange Tasks->"
"compatibleTypes": "->Exchange Tasks->Template Structure->"
},
"icon": "task-manager",
"properties": [
@@ -2505,6 +2505,9 @@
},
"level": 2,
"icon": "data-mine",
"initialValues": {
"code": "{ \n\"codeName\": \"Write here a name with no spaces or dashes.\"\n}"
},
"properties": [
{
"name": "sensorBots",
@@ -3056,6 +3059,7 @@
"actionFunction": "payload.onMenuItemClick"
}
],
"isTitleAllwaysVisible": true,
"addLeftIcons": true,
"level": 3,
"referenceAttachesTo": {
+2 -2
View File
@@ -198,8 +198,8 @@ function newSpeedometer () {
if (isNaN(label) === false) {
label = Number(label)
label = Math.trunc(label * Math.pow(10, thisObject.params.DECIMALS)) / Math.pow(10, thisObject.params.DECIMALS)
if (label === 0) { label = label.toFixed(2) } else { label = label.toLocaleString() }
label = dynamicDecimals(label, 2)
if (label === 0) { label = label.toFixed(2) }
}
// label = label.substring(0, 6)
@@ -160,111 +160,91 @@ function newUiObjectsFromNodes () {
let parentNodeDefinition = APP_SCHEMA_MAP.get(parentNode.type)
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 = APP_SCHEMA_MAP.get(object.type)
if (nodeDefinition.isHierarchyHead === true) {
parentNode.rootNodes.push(object)
createUiObject(true, object.type, object.name, object, parentNode, undefined)
return object
if (nodeDefinition === undefined) {
console.log('Cannot addUIOBject of ' + type + ' because that type it is not defined at the APP_SCHEMA.')
}
if (nodeDefinition.initialValues !== undefined) {
if (nodeDefinition.initialValues.code !== undefined) {
object.code = nodeDefinition.initialValues.code
}
}
if (nodeDefinition.isHierarchyHead === true) {
parentNode.rootNodes.push(object)
createUiObject(true, object.type, object.name, object, parentNode, undefined)
return object
}
/* For the cases where an node is not chained to its parent but to the one at the parent before it at its collection */
let chainParent = parentNode
if (nodeDefinition.chainedToSameType === true) {
if (parentNodeDefinition.properties !== undefined) {
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
let property = parentNodeDefinition.properties[i]
if (property.childType === type) {
if (property.type === 'array') {
if (parentNode[property.name] !== undefined) {
if (parentNode[property.name].length > 0) {
let nodeChildren = parentNode[property.name]
chainParent = nodeChildren[nodeChildren.length - 1]
}
}
}
}
}
}
}
/* Create Empty Arrays for properties of type Array */
if (nodeDefinition.properties !== undefined) {
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
if (property.type === 'array') {
object[property.name] = []
}
}
}
if (nodeDefinition !== undefined) {
if (nodeDefinition.initialValues !== undefined) {
if (nodeDefinition.initialValues.code !== undefined) {
object.code = nodeDefinition.initialValues.code
}
}
}
/* Connect to Parent */
let chainParent = parentNode
if (nodeDefinition.chainedToSameType === true) {
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.
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
let property = parentNodeDefinition.properties[i]
if (property.childType === type) {
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
parentNode[property.name] = object
previousPropertyName = property.name
if (property.type === 'array') {
if (parentNode[property.name] !== undefined) {
if (parentNode[property.name].length > 0) {
let nodeChildren = parentNode[property.name]
chainParent = nodeChildren[nodeChildren.length - 1]
}
}
break
case 'array': {
if (parentNode[property.name] === undefined) {
parentNode[property.name] = []
}
if (property.maxItems !== undefined) {
if (parentNode[property.name].length < property.maxItems) {
parentNode[property.name].push(object)
} else {
return // Object can not be created.
}
} else {
parentNode[property.name].push(object)
}
}
break
}
}
}
}
}
createUiObject(true, object.type, object.name, object, parentNode, chainParent)
/* Create Empty Arrays for properties of type Array */
if (nodeDefinition.properties !== undefined) {
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
if (property.type === 'array') {
object[property.name] = []
}
}
}
/* Auto Add more Children */
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]
if (nodeDefinition !== undefined) {
if (nodeDefinition.initialValues !== undefined) {
if (nodeDefinition.initialValues.code !== undefined) {
object.code = nodeDefinition.initialValues.code
}
}
}
/* Connect to Parent */
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.
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
let property = parentNodeDefinition.properties[i]
if (property.childType === type) {
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (property.autoAdd === true) {
addUIObject(object, property.childType)
previousPropertyName = property.name
}
parentNode[property.name] = object
previousPropertyName = property.name
}
}
break
case 'array': {
if (property.autoAdd === true) {
if (object[property.name] === undefined) {
object[property.name] = []
if (parentNode[property.name] === undefined) {
parentNode[property.name] = []
}
if (property.maxItems !== undefined) {
if (parentNode[property.name].length < property.maxItems) {
parentNode[property.name].push(object)
} else {
return // Object can not be created.
}
addUIObject(object, property.childType)
} else {
parentNode[property.name].push(object)
}
}
break
@@ -272,6 +252,38 @@ function newUiObjectsFromNodes () {
}
}
}
createUiObject(true, object.type, object.name, object, parentNode, chainParent)
/* Auto Add more Children */
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 (property.autoAdd === true) {
addUIObject(object, property.childType)
previousPropertyName = property.name
}
}
}
break
case 'array': {
if (property.autoAdd === true) {
if (object[property.name] === undefined) {
object[property.name] = []
}
addUIObject(object, property.childType)
}
}
break
}
}
}
return object
}
@@ -281,8 +281,8 @@ function newUiObjectConstructor () {
actionFunction: floatingObject.payload.onMenuItemClick,
label: undefined,
visible: true,
iconPathOn: 'quality',
iconPathOff: 'quality',
iconPathOn: 'help',
iconPathOff: 'help',
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
+5 -1
View File
@@ -274,7 +274,11 @@ function newDesignSpace () {
'template-structure',
'template-target',
'delink',
'detach'
'detach',
'help',
'key-a',
'key-m',
'key-r'
]
for (let i = 0; i < iconsNames.length; i++) {
+9 -3
View File
@@ -22,7 +22,10 @@ function drawContainerBackground (container, color, opacity, fitFunction) {
browserCanvasContext.fill()
}
function dynamicDecimals (value) {
function dynamicDecimals (value, minDecimals) {
if (minDecimals === undefined) {
minDecimals = 0
}
let decimals = 2
if (value < 1) { decimals = 4 }
if (Math.abs(Math.trunc(value * 100)) < 1) { decimals = 6 }
@@ -30,7 +33,7 @@ function dynamicDecimals (value) {
if (Math.abs(Math.trunc(value * 1000000)) < 1) { decimals = 10 }
if (Math.abs(Math.trunc(value * 100000000)) < 1) { decimals = 12 }
if (Math.abs(Math.trunc(value * 10000000000)) < 1) { value = 0; decimals = 0 }
if (Math.trunc(value) === value) { decimals = 0 }
if (Math.trunc(value) === value) { decimals = minDecimals }
let returnValue = Number(value).toFixed(decimals)
return returnValue
}
@@ -241,7 +244,7 @@ function removeTime (datetime) {
return dateOnly
}
function printLabel (labelToPrint, x, y, opacity, fontSize, color, center, container, fitFunction) {
function printLabel (labelToPrint, x, y, opacity, fontSize, color, center, container, fitFunction, noDecimals) {
let labelPoint
if (color === undefined) { color = UI_COLOR.DARK }
if (fontSize === undefined) { fontSize = 10 };
@@ -251,6 +254,9 @@ function printLabel (labelToPrint, x, y, opacity, fontSize, color, center, conta
if (isNaN(label) === false && label !== '') {
label = dynamicDecimals(labelToPrint)
label = label.toLocaleString()
if (noDecimals === true) {
label = Math.trunc(label)
}
}
let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO
+29 -2
View File
@@ -17,7 +17,6 @@ function newVideoRecorder () {
function recordCanvas () {
{
console.log(canvas.mouse.action, wheelAnimationCounter)
const DISTANCE_BETWEEN_ICONS = 35
const ICON_SIZES = 50
@@ -61,7 +60,35 @@ function newVideoRecorder () {
} else {
pointerIcon = mousePointerIcon
}
let key = canvas.mouse.event.key
if (key === undefined) { break }
switch (key.toLowerCase()) {
case 'Escape':
{
pointerIcon = canvas.designSpace.iconCollection.get('key-m')
break
}
case 'm':
{
pointerIcon = canvas.designSpace.iconCollection.get('key-m')
break
}
case 'a':
{
pointerIcon = canvas.designSpace.iconCollection.get('key-a')
break
}
case 'r':
{
pointerIcon = canvas.designSpace.iconCollection.get('key-r')
break
}
case 'c':
{
pointerIcon = canvas.designSpace.iconCollection.get('key-r')
break
}
}
break
}
case 'key up': {
+6 -4
View File
@@ -36,13 +36,15 @@ function newMarketFiles () {
let intervalHandle
let finalized = false
let eventSubscriptionIdDatasetUpdated
let eventSubscriptionIdDatasetUpdated = []
return thisObject
function finalize () {
try {
systemEventHandler.stopListening('Dataset Updated', eventSubscriptionIdDatasetUpdated)
for (let i = 0; i < eventSubscriptionIdDatasetUpdated.length; i++) {
systemEventHandler.stopListening('Dataset Updated', eventSubscriptionIdDatasetUpdated[i])
}
thisObject.eventHandler.finalize()
thisObject.eventHandler = undefined
@@ -112,7 +114,7 @@ function newMarketFiles () {
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE, thisObject)
function onResponse (message) {
eventSubscriptionIdDatasetUpdated = message.eventSubscriptionId
eventSubscriptionIdDatasetUpdated.push(message.eventSubscriptionId)
}
}
} catch (err) {
@@ -132,7 +134,7 @@ function newMarketFiles () {
try {
if (finalized === true) { return }
let updatedFiles = 0
console.log('updateFiles ' + periodName)
/* Now we will get the market files */
for (let i = 0; i < marketFilesPeriods.length; i++) {
@@ -542,26 +542,40 @@
let imageToDraw = strategyImages[record.number];
/* Draw the line that represents the duration of closed strategy */
/* Draw the line that represents the duration of closed strategy */
browserCanvasContext.beginPath();
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(recordPoint3.x + imageSize / 2, recordPoint3.y);
browserCanvasContext.lineTo(recordPoint4.x - imageSize / 2, recordPoint4.y);
browserCanvasContext.moveTo(recordPoint3.x + imageSize / 2, recordPoint3.y);
browserCanvasContext.lineTo(recordPoint4.x - imageSize / 2, recordPoint4.y);
browserCanvasContext.closePath();
browserCanvasContext.closePath();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.MANGANESE_PURPLE + ', 1)';
browserCanvasContext.lineWidth = 1
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.MANGANESE_PURPLE + ', 1)';
browserCanvasContext.lineWidth = 1
if (record.status === 1) {
browserCanvasContext.setLineDash([0, 0])
} else {
browserCanvasContext.setLineDash([2, 4])
}
browserCanvasContext.stroke()
if (record.status === 1) {
browserCanvasContext.setLineDash([0, 0])
} else {
browserCanvasContext.setLineDash([2, 4])
}
browserCanvasContext.stroke()
/* Draw the Area */
/*
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(recordPoint1.x, recordPoint2.y);
browserCanvasContext.lineTo(recordPoint3.x, recordPoint3.y);
browserCanvasContext.lineTo(recordPoint4.x, recordPoint4.y);
browserCanvasContext.lineTo(recordPoint2.x, recordPoint2.y);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.LIGHT_GREY + ', ' + 0.5 + ')';
browserCanvasContext.fill();
*/
/* Draw the Sticks */
drawStick(recordPoint1, recordPoint3);
drawStick(recordPoint2, recordPoint4);
@@ -522,11 +522,11 @@
if (record.status === 1) {
switch (record.exitType) {
case 1: {
line1 = 'Exit: STOP';
line1 = 'Stop Loss';
break;
}
case 2: {
line1 = 'Exit: TP';
line1 = 'Take Profit';
break;
}
}
@@ -689,7 +689,7 @@
browserCanvasContext.save();
browserCanvasContext.translate(recordPoint3.x + labelOffset.x, recordPoint3.y + labelOffset.y);
browserCanvasContext.rotate(-Math.PI / 2);
printLabel(recordLabel, 0, 0, '1', 8);
printLabel(recordLabel, 0, 0, '1', 8, undefined, undefined, undefined, undefined, true);
browserCanvasContext.restore();
}
@@ -23,7 +23,7 @@ function newMastersPlottersTradingSimulationTradingSimulationTradingSimulationAs
let lastRecord;
let upDownButton
const HEIGHT_FACTOR = 1
const HEIGHT_FACTOR = 1.25
return thisObject;
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,348 @@
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); }
}
}
}
@@ -0,0 +1,360 @@
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)
}
}
@@ -0,0 +1,799 @@
function newTradingEnginesPlottersTradingSimulationSimulationExecution() {
const MODULE_NAME = "Simulation Execution Plotter";
const INTENSIVE_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let thisObject = {
// Main functions and properties.
initialize: initialize,
finalize: finalize,
container: undefined,
fitFunction: undefined,
getContainer: getContainer,
setTimeFrame: setTimeFrame,
setDatetime: setDatetime,
setCoordinateSystem: setCoordinateSystem,
draw: draw
};
/* 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 coordinateSystem
let timeFrame; // This will hold the current Time Frame the user is at.
let datetime; // This will hold the current Datetime the user is at.
/* these are module specific variables: */
let fileSequence;
let plotElements = []; // This is where the elements to be plotted are stored before plotting.
let plotLines = []; // Here we store the lines of open positions.
let previousNotesSetKey;
let onMouseOverEventSuscriptionId
let offsetChangedEventSubscriptionId
let filesUpdatedEventSubscriptionId
let dimmensionsChangedEventSubscriptionId
let scaleChangedEventSubscriptionId
let userPositionDate
return thisObject;
function finalize() {
try {
/* Stop listening to the necesary events. */
thisObject.container.eventHandler.stopListening(onMouseOverEventSuscriptionId)
canvas.chartingSpace.viewport.eventHandler.stopListening(offsetChangedEventSubscriptionId);
fileSequence.eventHandler.stopListening(filesUpdatedEventSubscriptionId);
thisObject.container.eventHandler.stopListening(dimmensionsChangedEventSubscriptionId)
/* Destroyd References */
datetime = undefined;
timeFrame = undefined;
fileSequence = undefined;
plotElements = undefined;
plotLines = undefined;
thisObject.fitFunction = undefined
finalizeCoordinateSystem()
coordinateSystem = undefined
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] ' + MODULE_NAME + ' -> finalize -> err = " + err.stack.stack); }
}
}
function initialize(pStorage, pDatetime, pTimeFrame, pCoordinateSystem, callBackFunction) {
try {
datetime = pDatetime;
timeFrame = pTimeFrame;
coordinateSystem = pCoordinateSystem
initializeCoordinateSystem()
fileSequence = pStorage.fileSequences[0];
recalculate();
filesUpdatedEventSubscriptionId = fileSequence.eventHandler.listenToEvent("Files Updated", onFilesUpdated); // Only the first sequence is supported right now.
offsetChangedEventSubscriptionId = canvas.chartingSpace.viewport.eventHandler.listenToEvent("Position Changed", onViewportPositionChanged);
onMouseOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
/* Ready for when dimmension changes. */
dimmensionsChangedEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('Dimmensions Changed', function () {
recalculate();
})
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] ' + MODULE_NAME + ' -> initialize -> err = " + err.stack); }
callBackFunction(GLOBAL.CUSTOM_FAIL_RESPONSE);
}
}
function initializeCoordinateSystem() {
scaleChangedEventSubscriptionId = coordinateSystem.eventHandler.listenToEvent('Scale Changed', onScaleChanged)
}
function finalizeCoordinateSystem() {
coordinateSystem.eventHandler.stopListening(scaleChangedEventSubscriptionId)
}
function onScaleChanged() {
recalculate();
}
function onMouseOver(event) {
let userPosition = getDateFromPointAtBrowserCanvas(event, thisObject.container, coordinateSystem)
userPositionDate = userPosition.valueOf()
}
function getContainer(point) {
try {
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;
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] ' + MODULE_NAME + ' -> initialize -> err = " + err.stack); }
}
}
function onFilesUpdated() {
recalculate();
}
function setTimeFrame(pTimeFrame) {
timeFrame = pTimeFrame;
recalculate();
}
function setDatetime(pDatetime) {
datetime = pDatetime;
}
function setCoordinateSystem(pCoordinateSystem) {
finalizeCoordinateSystem()
coordinateSystem = pCoordinateSystem
initializeCoordinateSystem()
}
function onViewportPositionChanged() {
if (Math.random() * 100 > 95) {
recalculate()
}
}
function recalculate() {
try {
if (fileSequence === undefined) { return; }
/*
We are going to filter the records depending on the Time Frame. We want that for a 1 min time peroid all the records appears on screen,
but for higher periods, we will filter out some records, so that they do not overlap ever.
*/
plotElements = [];
plotLines = [];
let lastSellRate;
let lastSellDate;
let sellExecRate;
let lastBuyRate;
let lastBuyDate;
let buyExecRate;
let maxSequence = fileSequence.getFilesLoaded();
for (let j = 0; j < maxSequence; j++) {
let file = fileSequence.getFile(j);
let history = [];
let lines = [];
/* First the small balls */
const ONE_MIN_IN_MILISECONDS = 60 * 1000;
let step = timeFrame / ONE_MIN_IN_MILISECONDS;
step = 1; // For now we dont discard records depending on the zoom level.
let i = 0;
let lastRecordPushed = 0;
for (i = 0; i < file.length; i = i + step) {
let newHistoryRecord = {
date: Math.trunc(file[i][0] / 60000) * 60000 + 30000,
buyAvgRate: file[i][1],
sellAvgRate: file[i][2],
lastSellRate: file[i][3],
sellExecRate: file[i][4],
lastBuyRate: file[i][5],
buyExecRate: file[i][6],
marketRate: file[i][7],
newPositions: file[i][8],
newTrades: file[i][9],
movedPositions: file[i][10],
profitsAssetA: file[i][11],
profitsAssetB: file[i][12],
combinedProfitsA: file[i][13],
combinedProfitsB: file[i][14],
datetime: file[i][0]
};
/* Finally we add this History Record to the Array */
history.push(newHistoryRecord);
lastRecordPushed = i;
/* Here we build the lines. */
//if (timeFrame <= 1 * 60 * 1000) {
if (newHistoryRecord.lastSellRate > 0) {
lastSellRate = newHistoryRecord.lastSellRate;
lastSellDate = newHistoryRecord.date;
}
if (newHistoryRecord.sellExecRate > 0) {
let newLine = {
type: "sell",
x1: lastSellDate,
y1: lastSellRate,
x2: newHistoryRecord.date,
y2: newHistoryRecord.sellExecRate
};
lines.push(newLine);
}
if (newHistoryRecord.lastBuyRate > 0) {
lastBuyRate = newHistoryRecord.lastBuyRate;
lastBuyDate = newHistoryRecord.date;
}
if (newHistoryRecord.buyExecRate > 0) {
let newLine = {
type: "buy",
x1: lastBuyDate,
y1: lastBuyRate,
x2: newHistoryRecord.date,
y2: newHistoryRecord.buyExecRate
};
lines.push(newLine);
}
//}
}
/* We allways want to put the last record of the file on the filterd dataset, so as to allways show the latest advance of the bot. */
i = file.length - 1;
if (lastRecordPushed !== i) {
let newHistoryRecord = {
date: Math.trunc(file[i][0] / 60000) * 60000 + 30000,
buyAvgRate: file[i][1],
sellAvgRate: file[i][2],
lastSellRate: file[i][3],
sellExecRate: file[i][4],
lastBuyRate: file[i][5],
buyExecRate: file[i][6],
marketRate: file[i][7],
newPositions: file[i][8],
newTrades: file[i][9],
movedPositions: file[i][10],
profitsAssetA: file[i][11],
profitsAssetB: file[i][12],
combinedProfitsA: file[i][13],
combinedProfitsB: file[i][14]
};
history.push(newHistoryRecord);
}
for (let i = 0; i < file.length; i++) {
let newHistoryRecord = {
date: Math.trunc(file[i][0] / 60000) * 60000 + 30000,
buyAvgRate: file[i][1],
sellAvgRate: file[i][2],
lastSellRate: file[i][3],
sellExecRate: file[i][4],
lastBuyRate: file[i][5],
buyExecRate: file[i][6],
marketRate: file[i][7],
newPositions: file[i][8],
newTrades: file[i][9],
movedPositions: file[i][10],
profitsAssetA: file[i][11],
profitsAssetB: file[i][12],
combinedProfitsA: file[i][13],
combinedProfitsB: file[i][14]
};
}
plotElements.push(history);
plotLines.push(lines);
}
thisObject.container.eventHandler.raiseEvent("History Changed", history);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] ' + MODULE_NAME + ' -> recalculate -> err = " + err.stack); }
}
}
function draw() {
plotChart();
}
function plotChart() {
try {
let currentRecord
let point = {
x: 0,
y: 0
};
let history;
for (let j = 0; j < plotElements.length; j++) {
let history = plotElements[j];
for (let i = 0; i < history.length; i++) {
record = history[i];
currentRecord = record
let timestamp = record.date // Math.trunc(record.date / timeFrame) * timeFrame + timeFrame / 2;
point = {
x: timestamp,
y: record.marketRate
};
point = coordinateSystem.transformThisPoint(point);
point = transformThisPoint(point, thisObject.container);
if (point.x < canvas.chartingSpace.viewport.visibleArea.bottomLeft.x || point.x > canvas.chartingSpace.viewport.visibleArea.bottomRight.x) { continue; }
point = canvas.chartingSpace.viewport.fitIntoVisibleArea(point);
point = thisObject.fitFunction(point);
let isCurrentRecord = false;
if (userPositionDate >= record.date - 30000 && userPositionDate <= record.date + 30000 - 1) {
isCurrentRecord = true;
}
let opacity = '1';
let currentRadius = 10
/* Draw a red inverted triangle on exec sell */
if (record.sellExecRate > 0) {
opacity = '1';
let normalSize = 5
let extraSize = 0
if (isCurrentRecord) { extraSize = 5 }
let point1 = {
x: record.date,
y: record.sellExecRate
};
let point2 = {
x: record.date + timeFrame / 7 * (normalSize + extraSize),
y: record.sellExecRate
};
let point3 = {
x: record.date - timeFrame / 7 * (normalSize + extraSize),
y: record.sellExecRate
};
point1 = coordinateSystem.transformThisPoint(point1);
point1 = transformThisPoint(point1, thisObject.container);
point1 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point1);
point1 = thisObject.fitFunction(point1);
point2 = coordinateSystem.transformThisPoint(point2);
point2 = transformThisPoint(point2, thisObject.container);
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point2 = thisObject.fitFunction(point2);
point3 = coordinateSystem.transformThisPoint(point3);
point3 = transformThisPoint(point3, thisObject.container);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
point3 = thisObject.fitFunction(point3);
let diff = point2.x - point3.x;
point2.y = point2.y - diff;
point3.y = point3.y - diff;
currentRecord.timeFrame = diff
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
point2 = thisObject.fitFunction(point2);
point3 = thisObject.fitFunction(point3);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point1.x, point1.y);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ')';
if (isCurrentRecord === false) {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + opacity + ')';
} else {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + opacity + ')'; /* highlight the current record */
}
browserCanvasContext.fill();
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.lineWidth = 0.25;
browserCanvasContext.stroke();
}
/* Draw a green triangle on exec buy */
if (record.buyExecRate > 0) {
opacity = '1';
let normalSize = 5
let extraSize = 0
if (isCurrentRecord) { extraSize = 5 }
let point1 = {
x: record.date,
y: record.buyExecRate
};
let point2 = {
x: record.date + timeFrame / 7 * (normalSize + extraSize),
y: record.buyExecRate
};
let point3 = {
x: record.date - timeFrame / 7 * (normalSize + extraSize),
y: record.buyExecRate
};
point1 = coordinateSystem.transformThisPoint(point1);
point1 = transformThisPoint(point1, thisObject.container);
point1 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point1);
point1 = thisObject.fitFunction(point1);
point2 = coordinateSystem.transformThisPoint(point2);
point2 = transformThisPoint(point2, thisObject.container);
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point2 = thisObject.fitFunction(point2);
point3 = coordinateSystem.transformThisPoint(point3);
point3 = transformThisPoint(point3, thisObject.container);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
point3 = thisObject.fitFunction(point3);
let diff = point2.x - point3.x;
point2.y = point2.y + diff;
point3.y = point3.y + diff;
currentRecord.timeFrame = diff
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
point2 = thisObject.fitFunction(point2);
point3 = thisObject.fitFunction(point3);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point1.x, point1.y);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + opacity + ')';
if (isCurrentRecord === false) {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + opacity + ')';
} else {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + opacity + ')'; /* highlight the current record */
}
browserCanvasContext.fill();
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.lineWidth = 0.25;
browserCanvasContext.stroke();
}
/* Draw a red inverted triangle on sell */
if (record.lastSellRate > 0) {
opacity = '1';
let normalSize = 5
let extraSize = 0
if (isCurrentRecord) { extraSize = 5 }
let point1 = {
x: record.date,
y: record.lastSellRate
};
let point2 = {
x: record.date + timeFrame / 7 * (normalSize + extraSize),
y: record.lastSellRate
};
let point3 = {
x: record.date - timeFrame / 7 * (normalSize + extraSize),
y: record.lastSellRate
};
point1 = coordinateSystem.transformThisPoint(point1);
point1 = transformThisPoint(point1, thisObject.container);
point1 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point1);
point1 = thisObject.fitFunction(point1);
point2 = coordinateSystem.transformThisPoint(point2);
point2 = transformThisPoint(point2, thisObject.container);
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point2 = thisObject.fitFunction(point2);
point3 = coordinateSystem.transformThisPoint(point3);
point3 = transformThisPoint(point3, thisObject.container);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
point3 = thisObject.fitFunction(point3);
let diff = point2.x - point3.x;
point2.y = point2.y - diff;
point3.y = point3.y - diff;
currentRecord.timeFrame = diff
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
point2 = thisObject.fitFunction(point2);
point3 = thisObject.fitFunction(point3);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point1.x, point1.y);
browserCanvasContext.closePath();
if (isCurrentRecord === false) {
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + opacity + ')';
} else {
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + opacity + ')'; /* highlight the current record */
}
browserCanvasContext.fill();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + opacity + ')';
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.lineWidth = 0.25;
browserCanvasContext.stroke();
}
/* Draw a green triangle on buy */
if (record.lastBuyRate > 0) {
opacity = '1';
let normalSize = 5
let extraSize = 0
if (isCurrentRecord) { extraSize = 5 }
let point1 = {
x: record.date,
y: record.lastBuyRate
};
let point2 = {
x: record.date + timeFrame / 7 * (normalSize + extraSize),
y: record.lastBuyRate
};
let point3 = {
x: record.date - timeFrame / 7 * (normalSize + extraSize),
y: record.lastBuyRate
};
point1 = coordinateSystem.transformThisPoint(point1);
point1 = transformThisPoint(point1, thisObject.container);
point1 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point1);
point1 = thisObject.fitFunction(point1);
point2 = coordinateSystem.transformThisPoint(point2);
point2 = transformThisPoint(point2, thisObject.container);
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point2 = thisObject.fitFunction(point2);
point3 = coordinateSystem.transformThisPoint(point3);
point3 = transformThisPoint(point3, thisObject.container);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
point3 = thisObject.fitFunction(point3);
let diff = point2.x - point3.x;
point2.y = point2.y + diff;
point3.y = point3.y + diff;
currentRecord.timeFrame = diff
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
point2 = thisObject.fitFunction(point2);
point3 = thisObject.fitFunction(point3);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point1.x, point1.y);
browserCanvasContext.closePath();
if (isCurrentRecord === false) {
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + opacity + ')';
} else {
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + opacity + ')'; /* highlight the current record */
}
browserCanvasContext.fill();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + opacity + ')';
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.lineWidth = 0.25;
browserCanvasContext.stroke();
}
/* Send the current record to the panel */
if (userPositionDate >= record.date - 30000 && userPositionDate < record.date + 30000) {
thisObject.container.eventHandler.raiseEvent("Current Record Changed", currentRecord);
}
/* Circles */
let radius = 2;
currentRadius = 10
/* Outer Circle */
if (isCurrentRecord === true) {
browserCanvasContext.beginPath();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ')';
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + opacity + ')'; /* highlight the current record */
browserCanvasContext.arc(point.x, point.y, currentRadius, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
if (point.x < canvas.chartingSpace.viewport.visibleArea.topLeft.x + 50 || point.x > canvas.chartingSpace.viewport.visibleArea.bottomRight.x - 50) {/*we leave this history without fill. */ } else {
browserCanvasContext.fill();
}
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.lineWidth = 0.25;
browserCanvasContext.stroke();
}
/* Inner Circle */
browserCanvasContext.beginPath();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ')';
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GOLDEN_ORANGE + ', ' + opacity + ')';
browserCanvasContext.arc(point.x, point.y, radius, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
if (point.x < canvas.chartingSpace.viewport.visibleArea.topLeft.x + 50 || point.x > canvas.chartingSpace.viewport.visibleArea.bottomRight.x - 50) {/*we leave this history without fill. */ } else {
browserCanvasContext.fill();
}
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.lineWidth = 0.25;
browserCanvasContext.stroke();
}
/* Draw the lines connecting plot elements. */
let lines = plotLines[j];
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
opacity = '1';
let point1 = {
x: line.x1,
y: line.y1
};
let point2 = {
x: line.x2,
y: line.y2
};
point1 = coordinateSystem.transformThisPoint(point1);
point1 = transformThisPoint(point1, thisObject.container);
point1 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point1);
point1 = thisObject.fitFunction(point1);
point2 = coordinateSystem.transformThisPoint(point2);
point2 = transformThisPoint(point2, thisObject.container);
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point2 = thisObject.fitFunction(point2);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.closePath();
if (line.type === "sell") {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + opacity + ')';
} else {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + opacity + ')';
}
browserCanvasContext.setLineDash([4, 1])
browserCanvasContext.lineWidth = 0.25;
browserCanvasContext.stroke();
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] ' + MODULE_NAME + ' -> plotChart -> err = " + err.stack); }
}
}
}
@@ -0,0 +1,465 @@
function newTradingEnginesPlottersTradingSimulationSimulationExecutionSimulationExecutionPanel() {
let thisObject = {
fitFunction: undefined,
container: undefined,
isVisible: true,
onRecordChange: onRecordChange,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
};
let container = newContainer();
container.initialize();
thisObject.container = container;
container.frame.containerName = "Trading Execution";
let currentRecord;
let upDownButton
return thisObject;
function finalize() {
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.isVisible = undefined
currentRecord = undefined
upDownButton.finalize()
upDownButton = undefined
}
function initialize() {
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL;
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL * 2.5;
thisObject.container.frame.position.x = canvas.chartingSpace.viewport.visibleArea.topLeft.x + thisObject.container.frame.width * 4;
thisObject.container.frame.position.y = canvas.chartingSpace.viewport.visibleArea.topRight.y;
upDownButton = newUpDownButton()
upDownButton.parentContainer = thisObject.container
upDownButton.container.frame.parentFrame = thisObject.container.frame
upDownButton.fitFunction = thisObject.fitFunction
upDownButton.initialize()
}
function getContainer(point) {
if (thisObject.isVisible !== true) { return }
let container;
container = upDownButton.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 onRecordChange(lastCurrentCandle) {
currentRecord = lastCurrentCandle;
}
function draw() {
if (thisObject.isVisible !== true) { return }
thisObject.container.frame.draw(false, false, true, thisObject.fitFunction);
plot();
upDownButton.draw()
}
function plot() {
if (currentRecord === 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;
record = currentRecord
point = {
x: X_AXIS,
y: Y_AXIS
};
point = thisObject.container.frame.frameThisPoint(point);
point = thisObject.fitFunction(point);
let isCurrentRecord = true;
let radius = 2;
let currentRadius = 10
let opacity = '1';
/* Draw a red inverted triangle on exec sell */
if (record.sellExecRate > 0) {
opacity = '1';
let point1 = {
x: X_AXIS,
y: Y_AXIS
};
let point2 = {
x: X_AXIS + record.timeFrame / 4,
y: Y_AXIS
};
let point3 = {
x: X_AXIS - record.timeFrame / 4,
y: Y_AXIS
};
point1 = thisObject.container.frame.frameThisPoint(point1);
point1 = thisObject.fitFunction(point1);
point2 = thisObject.container.frame.frameThisPoint(point2);
point2 = thisObject.fitFunction(point2);
point3 = thisObject.container.frame.frameThisPoint(point3);
point3 = thisObject.fitFunction(point3);
let diff = point2.x - point3.x;
point2.y = point2.y - diff;
point3.y = point3.y - diff;
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point1.x, point1.y);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ')';
if (isCurrentRecord === false) {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + opacity + ')';
} else {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + opacity + ')'; /* highlight the current record */
}
browserCanvasContext.fill();
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.stroke();
}
/* Draw a green triangle on exec buy */
if (record.buyExecRate > 0) {
opacity = '1';
let point1 = {
x: X_AXIS,
y: Y_AXIS
};
let point2 = {
x: X_AXIS + record.timeFrame / 4,
y: Y_AXIS
};
let point3 = {
x: X_AXIS - record.timeFrame / 4,
y: Y_AXIS
};
point1 = thisObject.container.frame.frameThisPoint(point1);
point1 = thisObject.fitFunction(point1);
point2 = thisObject.container.frame.frameThisPoint(point2);
point2 = thisObject.fitFunction(point2);
point3 = thisObject.container.frame.frameThisPoint(point3);
point3 = thisObject.fitFunction(point3);
let diff = point2.x - point3.x;
point2.y = point2.y + diff;
point3.y = point3.y + diff;
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point1.x, point1.y);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + opacity + ')';
if (isCurrentRecord === false) {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + opacity + ')';
} else {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + opacity + ')'; /* highlight the current record */
}
browserCanvasContext.fill();
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.stroke();
}
/* Draw a red inverted triangle on sell */
if (record.lastSellRate > 0) {
opacity = '1';
let point1 = {
x: X_AXIS,
y: Y_AXIS
};
let point2 = {
x: X_AXIS + record.timeFrame / 4,
y: Y_AXIS
};
let point3 = {
x: X_AXIS - record.timeFrame / 4,
y: Y_AXIS
};
point1 = thisObject.container.frame.frameThisPoint(point1);
point1 = thisObject.fitFunction(point1);
point2 = thisObject.container.frame.frameThisPoint(point2);
point2 = thisObject.fitFunction(point2);
point3 = thisObject.container.frame.frameThisPoint(point3);
point3 = thisObject.fitFunction(point3);
let diff = point2.x - point3.x;
point2.y = point2.y - diff;
point3.y = point3.y - diff;
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point1.x, point1.y);
browserCanvasContext.closePath();
if (isCurrentRecord === false) {
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + opacity + ')';
} else {
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + opacity + ')'; /* highlight the current record */
}
browserCanvasContext.fill();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + opacity + ')';
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.stroke();
}
/* Draw a green triangle on buy */
if (record.lastBuyRate > 0) {
opacity = '1';
let point1 = {
x: X_AXIS,
y: Y_AXIS
};
let point2 = {
x: X_AXIS + record.timeFrame / 4,
y: Y_AXIS
};
let point3 = {
x: X_AXIS - record.timeFrame / 4,
y: Y_AXIS
};
point1 = thisObject.container.frame.frameThisPoint(point1);
point1 = thisObject.fitFunction(point1);
point2 = thisObject.container.frame.frameThisPoint(point2);
point2 = thisObject.fitFunction(point2);
point3 = thisObject.container.frame.frameThisPoint(point3);
point3 = thisObject.fitFunction(point3);
let diff = point2.x - point3.x;
point2.y = point2.y + diff;
point3.y = point3.y + diff;
point2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point2);
point3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(point3);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point1.x, point1.y);
browserCanvasContext.closePath();
if (isCurrentRecord === false) {
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + opacity + ')';
} else {
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + opacity + ')'; /* highlight the current record */
}
browserCanvasContext.fill();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + opacity + ')';
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.stroke();
}
browserCanvasContext.lineWidth = 0.25;
/* Outer Circle */
if (isCurrentRecord === true) {
browserCanvasContext.beginPath();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ')';
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + opacity + ')'; /* highlight the current record */
browserCanvasContext.arc(point.x, point.y, currentRadius, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
if (point.x < canvas.chartingSpace.viewport.visibleArea.topLeft.x + 50 || point.x > canvas.chartingSpace.viewport.visibleArea.bottomRight.x - 50) {/*we leave this history without fill. */ } else {
browserCanvasContext.fill();
}
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.stroke();
}
/* Inner Circle */
browserCanvasContext.beginPath();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ')';
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GOLDEN_ORANGE + ', ' + opacity + ')';
browserCanvasContext.arc(point.x, point.y, radius, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
if (point.x < canvas.chartingSpace.viewport.visibleArea.topLeft.x + 50 || point.x > canvas.chartingSpace.viewport.visibleArea.bottomRight.x - 50) {/*we leave this history without fill. */ } else {
browserCanvasContext.fill();
}
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.stroke();
/* put the labels */
browserCanvasContext.beginPath();
let y;
let recordDate = new Date(currentRecord.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('Sell Rate', X_AXIS, frameTitleHeight + frameBodyHeight * 0.15 / 2, '1');
printLabel(currentRecord.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('Buy Rate', X_AXIS, frameTitleHeight + frameBodyHeight * 0.35 / 2, '1');
printLabel(currentRecord.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('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('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('Datetime', X_AXIS, frameTitleHeight + frameBodyHeight * (1 - 0.05 / 2), '1');
printLabel(recordDate.toUTCString(), X_AXIS, frameTitleHeight + frameBodyHeight * (1 - 0.1 / 2), '0.50');
function printLabel(labelToPrint, x, y, opacity) {
let labelPoint;
let fontSize = 10;
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira';
let label = '' + labelToPrint;
if (isNaN(label) === false) {
label = Number(label).toLocaleString();
}
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();
}
}
@@ -0,0 +1,700 @@
function newTradingEnginesPlottersTradingSimulationStrategies() {
const MODULE_NAME = "Strategies Plotter";
const INFO_LOG = false;
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,
fitFunction: undefined,
getContainer: getContainer,
setTimeFrame: setTimeFrame,
setDatetime: setDatetime,
setCoordinateSystem: setCoordinateSystem,
draw: draw,
/* Events declared outside the plotter. */
onDailyFileLoaded: onDailyFileLoaded,
// Secondary functions and properties.
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 coordinateSystem
let timeFrame; // This will hold the current Time Frame the user is at.
let datetime; // This will hold the current Datetime the user is at.
let marketFile; // This is the current Market File being plotted.
let fileCursor; // This is the current File Cursor being used to retrieve Daily Files.
let marketFiles; // This object will provide the different Market Files at different Time Frames.
let dailyFiles; // This object will provide the different File Cursors at different Time Frames.
/* these are module specific variables: */
let strategies = [];
let strategyImages = [];
let onMouseOverEventSuscriptionId
let zoomChangedEventSubscriptionId
let offsetChangedEventSubscriptionId
let dragFinishedEventSubscriptionId
let dimmensionsChangedEventSubscriptionId
let marketFilesUpdatedEventSubscriptionId
let dailyFilesUpdatedEventSubscriptionId
let scaleChangedEventSubscriptionId
let userPositionDate
return thisObject;
function finalize() {
try {
if (INFO_LOG === true) { logger.write("[INFO] finalize -> Entering function."); }
/* Stop listening to the necesary events. */
thisObject.container.eventHandler.stopListening(onMouseOverEventSuscriptionId)
canvas.chartingSpace.viewport.eventHandler.stopListening(zoomChangedEventSubscriptionId);
canvas.chartingSpace.viewport.eventHandler.stopListening(offsetChangedEventSubscriptionId);
canvas.eventHandler.stopListening(dragFinishedEventSubscriptionId);
thisObject.container.eventHandler.stopListening(dimmensionsChangedEventSubscriptionId)
marketFiles.eventHandler.stopListening(marketFilesUpdatedEventSubscriptionId);
dailyFiles.eventHandler.stopListening(dailyFilesUpdatedEventSubscriptionId);
/* Destroyd References */
marketFiles = undefined;
dailyFiles = undefined;
datetime = undefined;
timeFrame = undefined;
marketFile = undefined;
fileCursor = undefined;
strategyImages = undefined;
thisObject.fitFunction = undefined
finalizeCoordinateSystem()
coordinateSystem = undefined
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] finalize -> err = " + err.stack); }
}
}
function initialize(pStorage, pDatetime, pTimeFrame, pCoordinateSystem, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
/* Store the information received. */
marketFiles = pStorage.marketFiles[0];
dailyFiles = pStorage.dailyFiles[0];
datetime = pDatetime;
timeFrame = pTimeFrame;
coordinateSystem = pCoordinateSystem
initializeCoordinateSystem()
/* We need a Market File in order to calculate the Y scale, since this scale depends on actual data. */
marketFile = marketFiles.getFile(ONE_DAY_IN_MILISECONDS); // This file is the one processed faster.
/* Now we set the right files according to current Period. */
marketFile = marketFiles.getFile(pTimeFrame);
fileCursor = dailyFiles.getFileCursor(pTimeFrame);
/* Listen to the necesary events. */
zoomChangedEventSubscriptionId = canvas.chartingSpace.viewport.eventHandler.listenToEvent("Zoom Changed", onViewportZoomChanged);
offsetChangedEventSubscriptionId = canvas.chartingSpace.viewport.eventHandler.listenToEvent("Position Changed", onViewportPositionChanged);
dragFinishedEventSubscriptionId = canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished);
marketFilesUpdatedEventSubscriptionId = marketFiles.eventHandler.listenToEvent("Files Updated", onMarketFilesUpdated);
dailyFilesUpdatedEventSubscriptionId = dailyFiles.eventHandler.listenToEvent("Files Updated", onDailyFilesUpdated);
onMouseOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
/* Get ready for plotting. */
recalculate();
/* Ready for when dimmension changes. */
dimmensionsChangedEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('Dimmensions Changed', function () {
recalculate();
})
for (let i = 1; i < 15; i++) {
let strategyImage = canvas.designSpace.iconByUiObjectType.get('Strategy');
strategyImages.push(strategyImage);
}
callBackFunction();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err.stack); }
}
}
function initializeCoordinateSystem() {
scaleChangedEventSubscriptionId = coordinateSystem.eventHandler.listenToEvent('Scale Changed', onScaleChanged)
}
function finalizeCoordinateSystem() {
coordinateSystem.eventHandler.stopListening(scaleChangedEventSubscriptionId)
}
function onScaleChanged() {
recalculate();
}
function onMouseOver(event) {
let userPosition = getDateFromPointAtBrowserCanvas(event, thisObject.container, coordinateSystem)
userPositionDate = userPosition.valueOf()
}
function getContainer(point) {
try {
if (INFO_LOG === true) { logger.write("[INFO] getContainer -> Entering function."); }
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;
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] getContainer -> err = " + err.stack); }
}
}
function onMarketFilesUpdated() {
try {
let newMarketFile = marketFiles.getFile(timeFrame);
if (newMarketFile !== undefined) {
marketFile = newMarketFile;
recalculate();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onMarketFilesUpdated -> err = " + err.stack); }
}
}
function onDailyFilesUpdated() {
try {
let newFileCursor = dailyFiles.getFileCursor(timeFrame);
if (newFileCursor !== undefined) {
fileCursor = newFileCursor;
recalculate();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onDailyFilesUpdated -> err = " + err.stack); }
}
}
function setTimeFrame(pTimeFrame) {
try {
if (timeFrame !== pTimeFrame) {
timeFrame = pTimeFrame;
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
marketFile = marketFiles.getFile(pTimeFrame);
recalculate();
} else {
let newFileCursor = dailyFiles.getFileCursor(pTimeFrame);
fileCursor = newFileCursor; // In this case, we explicitly want that if there is no valid cursor, we invalidate the data and show nothing.
recalculate();
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] setTimeFrame -> err = " + err.stack); }
}
}
function setDatetime(pDatetime) {
datetime = pDatetime;
}
function setCoordinateSystem(pCoordinateSystem) {
finalizeCoordinateSystem()
coordinateSystem = pCoordinateSystem
initializeCoordinateSystem()
}
function onDailyFileLoaded(event) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onDailyFileLoaded -> Entering function."); }
if (event.currentValue === event.totalValue) {
/* This happens only when all of the files in the cursor have been loaded. */
recalculate();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onDailyFileLoaded -> err = " + err.stack); }
}
}
function draw() {
try {
if (INTENSIVE_LOG === true) { logger.write("[INFO] draw -> Entering function."); }
this.container.frame.draw();
plotChart();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] draw -> err = " + err.stack); }
}
}
function recalculate() {
try {
strategies = []
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
recalculateUsingMarketFiles();
} else {
recalculateUsingDailyFiles();
}
thisObject.container.eventHandler.raiseEvent("Strategies Changed", strategies);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] recalculate -> err = " + err.stack); }
}
}
function recalculateUsingDailyFiles() {
try {
if (INFO_LOG === true) { logger.write("[INFO] recalculateUsingDailyFiles -> Entering function."); }
if (fileCursor === undefined) {
strategies = [];
return;
} // We need to wait
if (fileCursor.files.size === 0) {
strategies = [];
return;
} // We need to wait until there are files in the cursor
let daysOnSides = getSideDays(timeFrame);
let leftDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
let rightDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topRight, thisObject.container, coordinateSystem);
let dateDiff = rightDate.valueOf() - leftDate.valueOf();
let farLeftDate = new Date(leftDate.valueOf() - dateDiff * 1.5);
let farRightDate = new Date(rightDate.valueOf() + dateDiff * 1.5);
let currentDate = new Date(farLeftDate.valueOf());
strategies = [];
while (currentDate.valueOf() <= farRightDate.valueOf() + ONE_DAY_IN_MILISECONDS) {
let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2);
let dailyFile = fileCursor.files.get(stringDate);
if (dailyFile !== undefined) {
for (let i = 0; i < dailyFile.length; i++) {
let record = {
begin: undefined,
end: undefined,
status: undefined,
number: undefined,
beginRate: undefined,
endRate: undefined
};
record.begin = dailyFile[i][0];
record.end = dailyFile[i][1];
record.status = dailyFile[i][2];
record.number = dailyFile[i][3];
record.beginRate = dailyFile[i][4];
record.endRate = dailyFile[i][5];
if (
(record.begin >= farLeftDate.valueOf() && record.end <= farRightDate.valueOf()) &&
(record.begin >= coordinateSystem.min.x && record.end <= coordinateSystem.max.x)
) {
strategies.push(record);
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Strategy Changed", thisObject.currentRecord);
}
}
}
}
currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS);
}
/* Lests check if all the visible screen is going to be covered by strategies. */
let lowerEnd = leftDate.valueOf();
let upperEnd = rightDate.valueOf();
setTimeout(recalculate, 2000);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingDailyFiles -> err = " + err.stack); }
}
}
function recalculateUsingMarketFiles() {
try {
if (INFO_LOG === true) { logger.write("[INFO] recalculateUsingMarketFiles -> Entering function."); }
if (marketFile === undefined) { return; } // Initialization not complete yet.
let daysOnSides = getSideDays(timeFrame);
let leftDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
let rightDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topRight, thisObject.container, coordinateSystem);
let dateDiff = rightDate.valueOf() - leftDate.valueOf();
leftDate = new Date(leftDate.valueOf() - dateDiff * 1.5);
rightDate = new Date(rightDate.valueOf() + dateDiff * 1.5);
strategies = [];
for (let i = 0; i < marketFile.length; i++) {
let record = {
begin: undefined,
end: undefined,
status: undefined,
number: undefined,
beginRate: undefined,
endRate: undefined
};
record.begin = marketFile[i][0];
record.end = marketFile[i][1];
record.status = marketFile[i][2];
record.number = marketFile[i][3];
record.beginRate = marketFile[i][4];
record.endRate = marketFile[i][5];
if (record.begin >= leftDate.valueOf() && record.end <= rightDate.valueOf()) {
strategies.push(record);
if (
(record.begin >= leftDate.valueOf() && record.end <= rightDate.valueOf()) &&
(record.begin >= coordinateSystem.min.x && record.end <= coordinateSystem.max.x)
) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Strategy Changed", thisObject.currentRecord);
}
}
}
//console.log("Olivia > recalculateUsingMarketFiles > total strategies generated : " + strategies.length);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingMarketFiles -> err = " + err.stack); }
}
}
function plotChart() {
try {
thisObject.container.eventHandler.raiseEvent("Current Strategy Record Changed", undefined);
let record;
for (let i = 0; i < strategies.length; i++) {
record = strategies[i];
let recordPoint1 = {
x: record.begin,
y: record.beginRate
};
let recordPoint2 = {
x: record.end,
y: record.endRate
};
let recordPoint3 = {
x: record.begin,
y: record.beginRate
};
let recordPoint4 = {
x: record.end,
y: record.endRate
};
recordPoint1 = coordinateSystem.transformThisPoint(recordPoint1);
recordPoint2 = coordinateSystem.transformThisPoint(recordPoint2);
recordPoint3 = coordinateSystem.transformThisPoint(recordPoint3);
recordPoint4 = coordinateSystem.transformThisPoint(recordPoint4);
recordPoint1 = transformThisPoint(recordPoint1, thisObject.container);
recordPoint2 = transformThisPoint(recordPoint2, thisObject.container);
recordPoint3 = transformThisPoint(recordPoint3, thisObject.container);
recordPoint4 = transformThisPoint(recordPoint4, thisObject.container);
if (recordPoint2.x < canvas.chartingSpace.viewport.visibleArea.bottomLeft.x || recordPoint1.x > canvas.chartingSpace.viewport.visibleArea.bottomRight.x) {
continue;
}
recordPoint3.y = recordPoint1.y + 2000;
recordPoint4.y = recordPoint1.y + 2000;
recordPoint1 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint1);
recordPoint2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint2);
recordPoint3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint3);
recordPoint4 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint4);
recordPoint1 = thisObject.fitFunction(recordPoint1, undefined, 30);
recordPoint2 = thisObject.fitFunction(recordPoint2, undefined, 30);
recordPoint3 = thisObject.fitFunction(recordPoint3, undefined, 30);
recordPoint4 = thisObject.fitFunction(recordPoint4, undefined, 30);
let imageSize = 20;
let imageToDraw = strategyImages[record.number];
/* Draw the line that represents the duration of closed strategy */
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(recordPoint3.x + imageSize / 2, recordPoint3.y);
browserCanvasContext.lineTo(recordPoint4.x - imageSize / 2, recordPoint4.y);
browserCanvasContext.closePath();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.MANGANESE_PURPLE + ', 1)';
browserCanvasContext.lineWidth = 1
if (record.status === 1) {
browserCanvasContext.setLineDash([0, 0])
} else {
browserCanvasContext.setLineDash([2, 4])
}
browserCanvasContext.stroke()
/* Draw the Area */
/*
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(recordPoint1.x, recordPoint2.y);
browserCanvasContext.lineTo(recordPoint3.x, recordPoint3.y);
browserCanvasContext.lineTo(recordPoint4.x, recordPoint4.y);
browserCanvasContext.lineTo(recordPoint2.x, recordPoint2.y);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.LIGHT_GREY + ', ' + 0.5 + ')';
browserCanvasContext.fill();
*/
/* Draw the Sticks */
drawStick(recordPoint1, recordPoint3);
drawStick(recordPoint2, recordPoint4);
if (imageToDraw.canDrawIcon === true) {
browserCanvasContext.drawImage(imageToDraw, recordPoint3.x - imageSize / 2, recordPoint3.y - imageSize / 2, imageSize, imageSize);
if (record.status === 1) {
browserCanvasContext.drawImage(imageToDraw, recordPoint4.x - imageSize / 2, recordPoint4.y - imageSize / 2, imageSize, imageSize);
}
}
/* Send the current record to the panel */
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
let currentRecord = {
};
thisObject.container.eventHandler.raiseEvent("Current Strategy Record Changed", currentRecord);
}
function drawStick(point1, point2) {
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.closePath();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.DARK + ', 0.25)';
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
/* highlight the current record */
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)'; // Current record accroding to time
}
browserCanvasContext.setLineDash([4, 3])
browserCanvasContext.lineWidth = 0.5
browserCanvasContext.stroke()
browserCanvasContext.setLineDash([0, 0])
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] plotChart -> err = " + err.stack); }
}
}
function onViewportZoomChanged(event) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onViewportZoomChanged -> Entering function."); }
recalculate();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onViewportZoomChanged -> err = " + err.stack); }
}
}
function onViewportPositionChanged(event) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onViewportPositionChanged -> Entering function."); }
if (event !== undefined) {
if (event.recalculate === true) {
recalculate()
return
}
}
if (Math.random() * 100 > 95) {
recalculate()
};
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onViewportPositionChanged -> err = " + err.stack); }
}
}
function onDragFinished() {
try {
if (INFO_LOG === true) { logger.write("[INFO] onDragFinished -> Entering function."); }
recalculate();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onDragFinished -> err = " + err.stack); }
}
}
}
@@ -0,0 +1,683 @@
function newTradingEnginesPlottersTradingSimulationTrades() {
const MODULE_NAME = "Trades Plotter";
const INFO_LOG = false;
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,
fitFunction: undefined,
getContainer: getContainer,
setTimeFrame: setTimeFrame,
setDatetime: setDatetime,
setCoordinateSystem: setCoordinateSystem,
draw: draw,
/* Events declared outside the plotter. */
onDailyFileLoaded: onDailyFileLoaded,
// Secondary functions and properties.
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 coordinateSystem
let timeFrame; // This will hold the current Time Frame the user is at.
let datetime; // This will hold the current Datetime the user is at.
let marketFile; // This is the current Market File being plotted.
let fileCursor; // This is the current File Cursor being used to retrieve Daily Files.
let marketFiles; // This object will provide the different Market Files at different Time Frames.
let dailyFiles; // This object will provide the different File Cursors at different Time Frames.
/* these are module specific variables: */
let trades = [];
let headers;
let onMouseOverEventSuscriptionId
let zoomChangedEventSubscriptionId
let offsetChangedEventSubscriptionId
let dragFinishedEventSubscriptionId
let dimmensionsChangedEventSubscriptionId
let marketFilesUpdatedEventSubscriptionId
let dailyFilesUpdatedEventSubscriptionId
let scaleChangedEventSubscriptionId
let userPositionDate
return thisObject;
function finalize() {
try {
if (INFO_LOG === true) { logger.write("[INFO] finalize -> Entering function."); }
/* Stop listening to the necesary events. */
thisObject.container.eventHandler.stopListening(onMouseOverEventSuscriptionId)
canvas.chartingSpace.viewport.eventHandler.stopListening(zoomChangedEventSubscriptionId);
canvas.chartingSpace.viewport.eventHandler.stopListening(offsetChangedEventSubscriptionId);
canvas.eventHandler.stopListening(dragFinishedEventSubscriptionId);
thisObject.container.eventHandler.stopListening(dimmensionsChangedEventSubscriptionId)
marketFiles.eventHandler.stopListening(marketFilesUpdatedEventSubscriptionId);
dailyFiles.eventHandler.stopListening(dailyFilesUpdatedEventSubscriptionId);
/* Destroyd References */
marketFiles = undefined;
dailyFiles = undefined;
datetime = undefined;
timeFrame = undefined;
marketFile = undefined;
fileCursor = undefined;
thisObject.fitFunction = undefined
finalizeCoordinateSystem()
coordinateSystem = undefined
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] finalize -> err = " + err.stack); }
}
}
function initialize(pStorage, pDatetime, pTimeFrame, pCoordinateSystem, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
/* Store the information received. */
marketFiles = pStorage.marketFiles[0];
dailyFiles = pStorage.dailyFiles[0];
datetime = pDatetime;
timeFrame = pTimeFrame;
coordinateSystem = pCoordinateSystem
initializeCoordinateSystem()
/* We need a Market File in order to calculate the Y scale, since this scale depends on actual data. */
marketFile = marketFiles.getFile(ONE_DAY_IN_MILISECONDS); // This file is the one processed faster.
/* Now we set the right files according to current Period. */
marketFile = marketFiles.getFile(pTimeFrame);
fileCursor = dailyFiles.getFileCursor(pTimeFrame);
/* Listen to the necesary events. */
zoomChangedEventSubscriptionId = canvas.chartingSpace.viewport.eventHandler.listenToEvent("Zoom Changed", onViewportZoomChanged);
offsetChangedEventSubscriptionId = canvas.chartingSpace.viewport.eventHandler.listenToEvent("Position Changed", onViewportPositionChanged);
dragFinishedEventSubscriptionId = canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished);
marketFilesUpdatedEventSubscriptionId = marketFiles.eventHandler.listenToEvent("Files Updated", onMarketFilesUpdated);
dailyFilesUpdatedEventSubscriptionId = dailyFiles.eventHandler.listenToEvent("Files Updated", onDailyFilesUpdated);
onMouseOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
/* 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 initializeCoordinateSystem() {
scaleChangedEventSubscriptionId = coordinateSystem.eventHandler.listenToEvent('Scale Changed', onScaleChanged)
}
function finalizeCoordinateSystem() {
coordinateSystem.eventHandler.stopListening(scaleChangedEventSubscriptionId)
}
function onScaleChanged() {
recalculate();
}
function onMouseOver(event) {
let userPosition = getDateFromPointAtBrowserCanvas(event, thisObject.container, coordinateSystem)
userPositionDate = userPosition.valueOf()
}
function getContainer(point) {
try {
if (INFO_LOG === true) { logger.write("[INFO] getContainer -> Entering function."); }
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;
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] getContainer -> err = " + err.stack); }
}
}
function onMarketFilesUpdated() {
try {
let newMarketFile = marketFiles.getFile(timeFrame);
if (newMarketFile !== undefined) {
marketFile = newMarketFile;
recalculate();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onMarketFilesUpdated -> err = " + err.stack); }
}
}
function onDailyFilesUpdated() {
try {
let newFileCursor = dailyFiles.getFileCursor(timeFrame);
if (newFileCursor !== undefined) {
fileCursor = newFileCursor;
recalculate();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onDailyFilesUpdated -> err = " + err.stack); }
}
}
function setTimeFrame(pTimeFrame) {
try {
if (timeFrame !== pTimeFrame) {
timeFrame = pTimeFrame;
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
marketFile = marketFiles.getFile(pTimeFrame);
recalculate();
} else {
let newFileCursor = dailyFiles.getFileCursor(pTimeFrame);
fileCursor = newFileCursor; // In this case, we explicitly want that if there is no valid cursor, we invalidate the data and show nothing.
recalculate();
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] setTimeFrame -> err = " + err.stack); }
}
}
function setDatetime(pDatetime) {
datetime = pDatetime;
}
function setCoordinateSystem(pCoordinateSystem) {
finalizeCoordinateSystem()
coordinateSystem = pCoordinateSystem
initializeCoordinateSystem()
}
function onDailyFileLoaded(event) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onDailyFileLoaded -> Entering function."); }
if (event.currentValue === event.totalValue) {
/* This happens only when all of the files in the cursor have been loaded. */
recalculate();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onDailyFileLoaded -> err = " + err.stack); }
}
}
function draw() {
try {
if (INTENSIVE_LOG === true) { logger.write("[INFO] draw -> Entering function."); }
this.container.frame.draw();
plotChart();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] draw -> err = " + err.stack); }
}
}
function recalculate() {
try {
trades = []
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
recalculateUsingMarketFiles();
} else {
recalculateUsingDailyFiles();
}
thisObject.container.eventHandler.raiseEvent("Trades Changed", trades);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] recalculate -> err = " + err.stack); }
}
}
function recalculateUsingDailyFiles() {
try {
if (INFO_LOG === true) { logger.write("[INFO] recalculateUsingDailyFiles -> Entering function."); }
if (fileCursor === undefined) {
trades = [];
return;
} // We need to wait
if (fileCursor.files.size === 0) {
trades = [];
return;
} // We need to wait until there are files in the cursor
let daysOnSides = getSideDays(timeFrame);
let leftDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
let rightDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topRight, thisObject.container, coordinateSystem);
let dateDiff = rightDate.valueOf() - leftDate.valueOf();
let farLeftDate = new Date(leftDate.valueOf() - dateDiff * 1.5);
let farRightDate = new Date(rightDate.valueOf() + dateDiff * 1.5);
let currentDate = new Date(farLeftDate.valueOf());
trades = [];
while (currentDate.valueOf() <= farRightDate.valueOf() + ONE_DAY_IN_MILISECONDS) {
let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2);
let dailyFile = fileCursor.files.get(stringDate);
if (dailyFile !== undefined) {
for (let i = 0; i < dailyFile.length; i++) {
let record = {};
record.begin = dailyFile[i][0];
record.end = dailyFile[i][1];
record.status = dailyFile[i][2];
record.lastTradeROI = dailyFile[i][3];
record.beginRate = dailyFile[i][4];
record.endRate = dailyFile[i][5];
record.exitType = dailyFile[i][6];
if (
(record.begin >= farLeftDate.valueOf() && record.end <= farRightDate.valueOf()) &&
(record.begin >= coordinateSystem.min.x && record.end <= coordinateSystem.max.x)
) {
trades.push(record);
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Trade Changed", thisObject.currentRecord);
}
}
}
}
currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS);
}
/* Lests check if all the visible screen is going to be covered by trades. */
let lowerEnd = leftDate.valueOf();
let upperEnd = rightDate.valueOf();
setTimeout(recalculate, 2000);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingDailyFiles -> err = " + err.stack); }
}
}
function recalculateUsingMarketFiles() {
try {
if (INFO_LOG === true) { logger.write("[INFO] recalculateUsingMarketFiles -> Entering function."); }
if (marketFile === undefined) { return; } // Initialization not complete yet.
let daysOnSides = getSideDays(timeFrame);
let leftDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
let rightDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topRight, thisObject.container, coordinateSystem);
let dateDiff = rightDate.valueOf() - leftDate.valueOf();
leftDate = new Date(leftDate.valueOf() - dateDiff * 1.5);
rightDate = new Date(rightDate.valueOf() + dateDiff * 1.5);
trades = [];
for (let i = 0; i < marketFile.length; i++) {
let record = {};
record.begin = marketFile[i][0];
record.end = marketFile[i][1];
record.status = marketFile[i][2];
record.lastTradeROI = marketFile[i][3];
record.beginRate = marketFile[i][4];
record.endRate = marketFile[i][5];
record.exitType = marketFile[i][6];
if (
(record.begin >= leftDate.valueOf() && record.end <= rightDate.valueOf()) &&
(record.begin >= coordinateSystem.min.x && record.end <= coordinateSystem.max.x)
) {
trades.push(record);
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Trade Changed", thisObject.currentRecord);
}
}
}
//console.log("Olivia > recalculateUsingMarketFiles > total trades generated : " + trades.length);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingMarketFiles -> err = " + err.stack); }
}
}
function plotChart() {
try {
thisObject.container.eventHandler.raiseEvent("Current Trade Record Changed", undefined);
let record;
for (let i = 0; i < trades.length; i++) {
record = trades[i];
/* Send the current record to the panel */
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
let currentRecord = {
};
thisObject.container.eventHandler.raiseEvent("Current Trade Record Changed", currentRecord);
}
let recordPoint1 = {
x: record.begin,
y: record.beginRate
};
let recordPoint2 = {
x: record.end,
y: record.beginRate
};
let recordPoint3 = {
x: record.end,
y: record.endRate
};
recordPoint1 = coordinateSystem.transformThisPoint(recordPoint1);
recordPoint2 = coordinateSystem.transformThisPoint(recordPoint2);
recordPoint3 = coordinateSystem.transformThisPoint(recordPoint3);
recordPoint1 = transformThisPoint(recordPoint1, thisObject.container);
recordPoint2 = transformThisPoint(recordPoint2, thisObject.container);
recordPoint3 = transformThisPoint(recordPoint3, thisObject.container);
if (recordPoint2.x < canvas.chartingSpace.viewport.visibleArea.bottomLeft.x || recordPoint1.x > canvas.chartingSpace.viewport.visibleArea.bottomRight.x) {
continue;
}
recordPoint1 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint1);
recordPoint2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint2);
recordPoint3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint3);
recordPoint1 = thisObject.fitFunction(recordPoint1);
recordPoint2 = thisObject.fitFunction(recordPoint2);
recordPoint3 = thisObject.fitFunction(recordPoint3);
let line1 = '';
let line2 = '';
if (record.status === 1) {
switch (record.exitType) {
case 1: {
line1 = 'Stop Loss';
break;
}
case 2: {
line1 = 'Take Profit';
break;
}
}
} else {
line1 = 'Open Position';
}
if (record.lastTradeROI < 0) {
line2 = 'ROI:' + (record.lastTradeROI).toFixed(2) + ' %';
} else {
line2 = 'ROI:' + (record.lastTradeROI).toFixed(2) + ' %';
}
/* Draw the triangle that represents the trade. */
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(recordPoint1.x, recordPoint1.y);
browserCanvasContext.lineTo(recordPoint2.x, recordPoint2.y);
browserCanvasContext.lineTo(recordPoint3.x, recordPoint3.y);
browserCanvasContext.closePath();
let opacity = '0.25';
if (record.lastTradeROI > 0) {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + opacity + ')';
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + opacity + ')';
} else {
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + opacity + ')';
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ')';
}
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + opacity + ')';
}
browserCanvasContext.fill();
browserCanvasContext.lineWidth = 1;
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.stroke();
let point = {}
if (record.beginRate > record.endRate) {
point.x = recordPoint3.x
point.y = recordPoint3.y + 100
} else {
point.x = recordPoint3.x
point.y = recordPoint3.y - 100
}
point = canvas.chartingSpace.viewport.fitIntoVisibleArea(point);
point = thisObject.fitFunction(point, undefined, 50);
if (
recordPoint3.x < canvas.chartingSpace.viewport.visibleArea.topLeft.x + 250
||
recordPoint3.x > canvas.chartingSpace.viewport.visibleArea.bottomRight.x - 250
||
recordPoint3.y > canvas.chartingSpace.viewport.visibleArea.bottomRight.y - 150
||
recordPoint3.y < canvas.chartingSpace.viewport.visibleArea.topLeft.y + 150
) {
// we do not write any text
} else {
printLabel(line1, recordPoint2.x - (recordPoint2.x - recordPoint1.x) / 2 - line1.length * FONT_ASPECT_RATIO, point.y, '1', 12);
printLabel(line2, recordPoint2.x - (recordPoint2.x - recordPoint1.x) / 2 - line2.length * FONT_ASPECT_RATIO, point.y + 15, '1', 12);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] plotChart -> err = " + err.stack); }
}
}
function onViewportZoomChanged(event) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onViewportZoomChanged -> Entering function."); }
recalculate();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onViewportZoomChanged -> err = " + err.stack); }
}
}
function onViewportPositionChanged(event) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onViewportPositionChanged -> Entering function."); }
if (event !== undefined) {
if (event.recalculate === true) {
recalculate()
return
}
}
if (Math.random() * 100 > 95) {
recalculate()
};
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onViewportPositionChanged -> err = " + err.stack); }
}
}
function onDragFinished() {
try {
if (INFO_LOG === true) { logger.write("[INFO] onDragFinished -> Entering function."); }
recalculate();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onDragFinished -> err = " + err.stack); }
}
}
}
@@ -0,0 +1,869 @@
function newTradingEnginesPlottersTradingSimulationTradingSimulation() {
const MODULE_NAME = "Simulation 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,
fitFunction: undefined,
getContainer: getContainer,
setTimeFrame: setTimeFrame,
setDatetime: setDatetime,
setCoordinateSystem: setCoordinateSystem,
draw: draw,
/* Events declared outside the plotter. */
onDailyFileLoaded: onDailyFileLoaded,
// Secondary functions and properties.
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 coordinateSystem
let timeFrame; // This will hold the current Time Frame the user is at.
let datetime; // This will hold the current Datetime the user is at.
let marketFile; // This is the current Market File being plotted.
let fileCursor; // This is the current File Cursor being used to retrieve Daily Files.
let marketFiles; // This object will provide the different Market Files at different Time Frames.
let dailyFiles; // This object will provide the different File Cursors at different Time Frames.
/* 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 onMouseOverEventSuscriptionId
let zoomChangedEventSubscriptionId
let offsetChangedEventSubscriptionId
let dragFinishedEventSubscriptionId
let dimmensionsChangedEventSubscriptionId
let marketFilesUpdatedEventSubscriptionId
let dailyFilesUpdatedEventSubscriptionId
let scaleChangedEventSubscriptionId
let userPositionDate
return thisObject;
function finalize() {
try {
/* Stop listening to the necesary events. */
thisObject.container.eventHandler.stopListening(onMouseOverEventSuscriptionId)
canvas.chartingSpace.viewport.eventHandler.stopListening(zoomChangedEventSubscriptionId);
canvas.chartingSpace.viewport.eventHandler.stopListening(offsetChangedEventSubscriptionId);
canvas.eventHandler.stopListening(dragFinishedEventSubscriptionId);
thisObject.container.eventHandler.stopListening(dimmensionsChangedEventSubscriptionId)
marketFiles.eventHandler.stopListening(marketFilesUpdatedEventSubscriptionId);
dailyFiles.eventHandler.stopListening(dailyFilesUpdatedEventSubscriptionId);
/* icons */
imageStopLossPhase = undefined;
imageTakeProfitPhase = undefined;
imageRecord = undefined;
/* Destroy References */
marketFiles = undefined;
dailyFiles = undefined;
datetime = undefined;
timeFrame = undefined;
marketFile = undefined;
fileCursor = undefined;
thisObject.fitFunction = undefined
finalizeCoordinateSystem()
coordinateSystem = undefined
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] finalize -> err = " + err.stack); }
}
}
function initialize(pStorage, pDatetime, pTimeFrame, pCoordinateSystem, callBackFunction) {
try {
/* Store the information received. */
marketFiles = pStorage.marketFiles[0];
dailyFiles = pStorage.dailyFiles[0];
datetime = pDatetime;
timeFrame = pTimeFrame;
coordinateSystem = pCoordinateSystem
initializeCoordinateSystem()
/* We need a Market File in order to calculate the Y scale, since this scale depends on actual data. */
marketFile = marketFiles.getFile(ONE_DAY_IN_MILISECONDS); // This file is the one processed faster.
/* Now we set the right files according to current Period. */
marketFile = marketFiles.getFile(pTimeFrame);
fileCursor = dailyFiles.getFileCursor(pTimeFrame);
/* Listen to the necesary events. */
zoomChangedEventSubscriptionId = canvas.chartingSpace.viewport.eventHandler.listenToEvent("Zoom Changed", onViewportZoomChanged);
offsetChangedEventSubscriptionId = canvas.chartingSpace.viewport.eventHandler.listenToEvent("Position Changed", onViewportPositionChanged);
dragFinishedEventSubscriptionId = canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished);
marketFilesUpdatedEventSubscriptionId = marketFiles.eventHandler.listenToEvent("Files Updated", onMarketFilesUpdated);
dailyFilesUpdatedEventSubscriptionId = dailyFiles.eventHandler.listenToEvent("Files Updated", onDailyFilesUpdated);
onMouseOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
/* Get ready for plotting. */
recalculate();
/* Ready for when dimmension changes. */
dimmensionsChangedEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('Dimmensions Changed', function () {
recalculate();
})
/* Loading a few icons */
imageStopLossPhase = canvas.designSpace.iconByUiObjectType.get('Stop');
imageTakeProfitPhase = canvas.designSpace.iconByUiObjectType.get('Phase');
imageRecord = canvas.designSpace.iconByUiObjectType.get('Trading System');
callBackFunction();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err.stack); }
}
}
function initializeCoordinateSystem() {
scaleChangedEventSubscriptionId = coordinateSystem.eventHandler.listenToEvent('Scale Changed', onScaleChanged)
}
function finalizeCoordinateSystem() {
coordinateSystem.eventHandler.stopListening(scaleChangedEventSubscriptionId)
}
function onScaleChanged() {
recalculate();
}
function onMouseOver(event) {
let userPosition = getDateFromPointAtBrowserCanvas(event, thisObject.container, coordinateSystem)
userPositionDate = userPosition.valueOf()
}
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 onMarketFilesUpdated() {
try {
let newMarketFile = marketFiles.getFile(timeFrame);
if (newMarketFile !== undefined) {
marketFile = newMarketFile;
recalculate();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onMarketFilesUpdated -> err = " + err.stack); }
}
}
function onDailyFilesUpdated() {
try {
let newFileCursor = dailyFiles.getFileCursor(timeFrame);
if (newFileCursor !== undefined) {
fileCursor = newFileCursor;
recalculate();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onDailyFilesUpdated -> err = " + err.stack); }
}
}
function setTimeFrame(pTimeFrame) {
try {
if (timeFrame !== pTimeFrame) {
timeFrame = pTimeFrame;
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
marketFile = marketFiles.getFile(pTimeFrame);
recalculate();
} else {
let newFileCursor = dailyFiles.getFileCursor(pTimeFrame);
fileCursor = newFileCursor; // In this case, we explicitly want that if there is no valid cursor, we invalidate the data and show nothing.
recalculate();
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] setTimeFrame -> err = " + err.stack); }
}
}
function setDatetime(pDatetime) {
datetime = pDatetime;
}
function setCoordinateSystem(pCoordinateSystem) {
finalizeCoordinateSystem()
coordinateSystem = pCoordinateSystem
initializeCoordinateSystem()
}
function onDailyFileLoaded(event) {
try {
if (event.currentValue === event.totalValue) {
/* This happens only when all of the files in the cursor have been loaded. */
recalculate();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onDailyFileLoaded -> err = " + err.stack); }
}
}
function draw() {
try {
if (INTENSIVE_LOG === true) { logger.write("[INFO] draw -> Entering function."); }
this.container.frame.draw();
plotChart();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] draw -> err = " + err.stack); }
}
}
function recalculate() {
try {
records = []
if (timeFrame >= _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 recalculateUsingDailyFiles() {
try {
if (fileCursor === undefined) {
records = [];
return;
} // We need to wait
if (fileCursor.files.size === 0) {
records = [];
return;
} // We need to wait until there are files in the cursor
let daysOnSides = getSideDays(timeFrame);
let leftDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
let rightDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topRight, thisObject.container, coordinateSystem);
let dateDiff = rightDate.valueOf() - leftDate.valueOf();
let farLeftDate = new Date(leftDate.valueOf() - dateDiff * 1.5);
let farRightDate = new Date(rightDate.valueOf() + dateDiff * 1.5);
let currentDate = new Date(farLeftDate.valueOf());
records = [];
while (currentDate.valueOf() <= farRightDate.valueOf() + ONE_DAY_IN_MILISECONDS) {
let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2);
let dailyFile = fileCursor.files.get(stringDate);
if (dailyFile !== undefined) {
for (let i = 0; i < dailyFile.length; i++) {
let record = {};
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.positionPeriods = dailyFile[i][35];
record.positionDays = dailyFile[i][36];
if (
(record.begin >= farLeftDate.valueOf() && record.end <= farRightDate.valueOf()) &&
(record.begin >= coordinateSystem.min.x && record.end <= coordinateSystem.max.x)
) {
records.push(record);
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.currentRecord);
}
}
}
}
currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS);
}
/* Lests check if all the visible screen is going to be covered by records. */
let lowerEnd = leftDate.valueOf();
let upperEnd = rightDate.valueOf();
setTimeout(recalculate, 2000);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingDailyFiles -> err = " + err.stack); }
}
}
function recalculateUsingMarketFiles() {
try {
if (marketFile === undefined) { return; } // Initialization not complete yet.
let daysOnSides = getSideDays(timeFrame);
let leftDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
let rightDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topRight, thisObject.container, coordinateSystem);
let dateDiff = rightDate.valueOf() - leftDate.valueOf();
leftDate = new Date(leftDate.valueOf() - dateDiff * 1.5);
rightDate = new Date(rightDate.valueOf() + dateDiff * 1.5);
records = [];
for (let i = 0; i < marketFile.length; i++) {
let record = {};
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.positionPeriods = marketFile[i][35];
record.positionDays = marketFile[i][36];
if (
(record.begin >= leftDate.valueOf() && record.end <= rightDate.valueOf()) &&
(record.begin >= coordinateSystem.min.x && record.end <= coordinateSystem.max.x)
) {
records.push(record);
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record;
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.currentRecord);
}
}
}
//console.log("Olivia > recalculateUsingMarketFiles > total records generated : " + records.length);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingMarketFiles -> err = " + err.stack); }
}
}
function plotChart() {
try {
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];
/* Contributing to Auto-Scale*/
if (record.stopLoss !== 0) {
coordinateSystem.reportYValue(record.stopLoss)
}
if (record.takeProfit !== 0) {
coordinateSystem.reportYValue(record.takeProfit)
}
/* Send the current record to the panel */
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
let eventRecords = {
currentRecord: record
};
thisObject.container.eventHandler.raiseEvent("Current Record Changed", eventRecords);
}
let stopLossPhase = -1;
let takeProfitPhase = -1;
if (i > 0) {
if (record.stopLossPhase !== records[i - 1].stopLossPhase) {
stopLossPhase = record.stopLossPhase;
}
if (record.takeProfitPhase !== records[i - 1].takeProfitPhase) {
takeProfitPhase = record.takeProfitPhase;
}
}
let recordPoint1 = {
x: record.begin + timeFrame / 7 * 1.5,
y: thisObject.container.frame.height
};
let recordPoint2 = {
x: record.end + timeFrame / 7 * 5.5,
y: thisObject.container.frame.height
};
let recordPoint3 = {
x: recordPoint1.x + (recordPoint2.x - recordPoint1.x) / 2,
y: 0
};
let recordPoint4 = {
x: record.begin + timeFrame / 7 * 1.5,
y: thisObject.container.frame.height * 100
};
let recordPoint5 = {
x: record.begin,
y: record.stopLoss
};
let recordPoint6 = {
x: record.end,
y: record.stopLoss
};
if (record.stopLoss === 0) { // Put these points out of range if stopLoss is zero.
recordPoint5.x = 0;
recordPoint6.x = 0;
}
let recordPoint7 = {
x: record.begin,
y: record.sellRate
};
let recordPoint8 = {
x: record.end,
y: record.sellRate
};
if (record.sellRate === 0) { // Put these points out of range if sellRate is zero.
recordPoint7.x = 0;
recordPoint8.x = 0;
}
let recordPoint9 = {
x: record.begin,
y: record.takeProfit
};
let recordPoint10 = {
x: record.end,
y: record.takeProfit
};
if (record.takeProfit === 0) { // Put these points out of range if takeProfit is zero.
recordPoint9.x = 0;
recordPoint10.x = 0;
}
recordPoint1 = coordinateSystem.transformThisPoint(recordPoint1);
recordPoint2 = coordinateSystem.transformThisPoint(recordPoint2);
recordPoint3 = coordinateSystem.transformThisPoint(recordPoint3);
recordPoint4 = coordinateSystem.transformThisPoint(recordPoint4);
recordPoint5 = coordinateSystem.transformThisPoint(recordPoint5);
recordPoint6 = coordinateSystem.transformThisPoint(recordPoint6);
recordPoint7 = coordinateSystem.transformThisPoint(recordPoint7);
recordPoint8 = coordinateSystem.transformThisPoint(recordPoint8);
recordPoint9 = coordinateSystem.transformThisPoint(recordPoint9);
recordPoint10 = coordinateSystem.transformThisPoint(recordPoint10);
recordPoint1 = transformThisPoint(recordPoint1, thisObject.container);
recordPoint2 = transformThisPoint(recordPoint2, thisObject.container);
recordPoint3 = transformThisPoint(recordPoint3, thisObject.container);
recordPoint4 = transformThisPoint(recordPoint4, thisObject.container);
recordPoint5 = transformThisPoint(recordPoint5, thisObject.container);
recordPoint6 = transformThisPoint(recordPoint6, thisObject.container);
recordPoint7 = transformThisPoint(recordPoint7, thisObject.container);
recordPoint8 = transformThisPoint(recordPoint8, thisObject.container);
recordPoint9 = transformThisPoint(recordPoint9, thisObject.container);
recordPoint10 = transformThisPoint(recordPoint10, thisObject.container);
recordPoint1 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint1);
recordPoint2 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint2);
recordPoint3 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint3);
recordPoint4 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint4);
recordPoint5 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint5);
recordPoint6 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint6);
recordPoint7 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint7);
recordPoint8 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint8);
recordPoint9 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint9);
recordPoint10 = canvas.chartingSpace.viewport.fitIntoVisibleArea(recordPoint10);
recordPoint1 = thisObject.fitFunction(recordPoint1);
recordPoint2 = thisObject.fitFunction(recordPoint2);
recordPoint3 = thisObject.fitFunction(recordPoint3);
recordPoint4 = thisObject.fitFunction(recordPoint4);
recordPoint5 = thisObject.fitFunction(recordPoint5);
recordPoint6 = thisObject.fitFunction(recordPoint6);
recordPoint7 = thisObject.fitFunction(recordPoint7);
recordPoint8 = thisObject.fitFunction(recordPoint8);
recordPoint9 = thisObject.fitFunction(recordPoint9);
recordPoint10 = thisObject.fitFunction(recordPoint10);
/* Image representing a Record */
let imageOffset = {
x: 0,
y: -30
}
let imageSize = (recordPoint2.x - recordPoint1.x) / 2;
let recordLabel = record.periods.toLocaleString()
if (imageSize < 8) {
if (recordLabel[recordLabel.length - 1] !== '0' || imageSize < 4)
recordLabel = ''
}
let labelOffset = {
x: 0 - imageSize / 2 + 3 + imageOffset.x,
y: -2 - imageOffset.y
}
let imagePosition = {
x: recordPoint4.x + imageOffset.x,
y: 0
}
imagePosition = canvas.chartingSpace.viewport.fitIntoVisibleArea(imagePosition)
imagePosition = thisObject.fitFunction(imagePosition, undefined, 0, 0, imageSize)
if (imageRecord.canDrawIcon === true) {
browserCanvasContext.drawImage(imageRecord, imagePosition.x, imagePosition.y, imageSize, imageSize);
browserCanvasContext.save();
browserCanvasContext.translate(recordPoint3.x + labelOffset.x, recordPoint3.y + labelOffset.y);
browserCanvasContext.rotate(-Math.PI / 2);
printLabel(recordLabel, 0, 0, '1', 8, undefined, undefined, undefined, undefined, true);
browserCanvasContext.restore();
}
if (recordPoint5.x < canvas.chartingSpace.viewport.visibleArea.bottomLeft.x || recordPoint5.x > canvas.chartingSpace.viewport.visibleArea.bottomRight.x) {
continue;
}
/* Next we are drawing the position Rate */
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(recordPoint7.x, recordPoint7.y);
browserCanvasContext.lineTo(recordPoint8.x, recordPoint8.y);
browserCanvasContext.closePath();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.MANGANESE_PURPLE + ', 1)';
browserCanvasContext.lineWidth = 1
browserCanvasContext.setLineDash([1, 4])
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
browserCanvasContext.lineWidth = 5
browserCanvasContext.setLineDash([3, 4])
/* highlight the current record */
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)'; // Current record accroding to time
}
browserCanvasContext.stroke()
browserCanvasContext.setLineDash([0, 0])
imageSize = 20;
let imageToDraw;
/* Depending on what is on top, it is also the text and image of the take profit / stop loss */
let yOffset = 0
if (record.takeProfit > record.stopLoss) { yOffset = imageSize * 2 }
/* Next we are drawing the stopLoss floor / ceilling */
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(recordPoint5.x, recordPoint5.y);
browserCanvasContext.lineTo(recordPoint6.x, recordPoint6.y);
browserCanvasContext.closePath();
let opacity = 1
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + '';
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
/* highlight the current record */
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)'; // Current record accroding to time
}
browserCanvasContext.lineWidth = 1
browserCanvasContext.stroke()
imagePosition = {
x: recordPoint6.x - imageSize,
y: recordPoint6.y - imageSize * 1.25 + yOffset
}
imagePosition = canvas.chartingSpace.viewport.fitIntoVisibleArea(imagePosition)
imagePosition = thisObject.fitFunction(imagePosition, undefined, 0, 0, imageSize)
let labelPosition = {
x: recordPoint6.x - imageSize / 2 - 3,
y: recordPoint6.y - imageSize * 1.5 + yOffset * 2
}
labelPosition = canvas.chartingSpace.viewport.fitIntoVisibleArea(labelPosition)
labelPosition = thisObject.fitFunction(labelPosition, undefined, 30)
if (imageStopLossPhase.canDrawIcon === true && stopLossPhase > -1) {
browserCanvasContext.drawImage(imageStopLossPhase, imagePosition.x, imagePosition.y, imageSize, imageSize);
printLabel(stopLossPhase, labelPosition.x, labelPosition.y, '1', 9);
}
/* Next we are drawing the Take Profit */
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(recordPoint9.x, recordPoint9.y);
browserCanvasContext.lineTo(recordPoint10.x, recordPoint10.y);
browserCanvasContext.closePath();
opacity = 1
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + opacity + '';
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
/* highlight the current record */
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)'; // Current record accroding to time
}
browserCanvasContext.lineWidth = 1
browserCanvasContext.stroke()
imagePosition = {
x: recordPoint10.x - imageSize * 2 / 3,
y: recordPoint10.y + imageSize / 4 - yOffset
}
imagePosition = canvas.chartingSpace.viewport.fitIntoVisibleArea(imagePosition)
imagePosition = thisObject.fitFunction(imagePosition, undefined, 0, 0, imageSize)
labelPosition = {
x: recordPoint10.x - imageSize * 1 / 3,
y: recordPoint10.y + imageSize * 1.9 - yOffset * 2
}
labelPosition = canvas.chartingSpace.viewport.fitIntoVisibleArea(labelPosition)
labelPosition = thisObject.fitFunction(labelPosition, undefined, 30)
if (imageTakeProfitPhase.canDrawIcon === true && takeProfitPhase > -1) {
browserCanvasContext.drawImage(imageTakeProfitPhase, imagePosition.x, imagePosition.y, imageSize, imageSize);
printLabel(takeProfitPhase, labelPosition.x, labelPosition.y, '1', 9);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] plotChart -> err = " + err.stack); }
}
}
function onViewportZoomChanged(event) {
try {
recalculate();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onViewportZoomChanged -> err = " + err.stack); }
}
}
function onViewportPositionChanged(event) {
try {
if (event !== undefined) {
if (event.recalculate === true) {
recalculate()
return
}
}
if (Math.random() * 100 > 95) {
recalculate()
};
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onViewportPositionChanged -> err = " + err.stack); }
}
}
function onDragFinished() {
try {
recalculate();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onDragFinished -> err = " + err.stack); }
}
}
}
@@ -0,0 +1,188 @@
function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimulationAssetBalancesPanel() {
let thisObject = {
fitFunction: undefined,
onRecordChange: onRecordChange,
container: undefined,
session: undefined,
isVisible: true,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
};
let container = newContainer();
container.initialize();
thisObject.container = container;
container.frame.containerName = "Simulation Asset Balances Panel";
let currentRecord;
let lastRecord;
let upDownButton
const HEIGHT_FACTOR = 1.25
return thisObject;
function initialize() {
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL * 1;
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL * HEIGHT_FACTOR;
thisObject.container.frame.position.x = canvas.chartingSpace.viewport.visibleArea.topRight.x - thisObject.container.frame.width * 1;
thisObject.container.frame.position.y = canvas.chartingSpace.viewport.visibleArea.topRight.y;
upDownButton = newUpDownButton()
upDownButton.parentContainer = thisObject.container
upDownButton.container.frame.parentFrame = thisObject.container.frame
upDownButton.fitFunction = thisObject.fitFunction
upDownButton.initialize()
thisObject.assetBalances = newAssetalances()
thisObject.assetBalances.container.connectToParent(thisObject.container, true, true)
thisObject.assetBalances.initialize()
}
function finalize() {
thisObject.session = undefined
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.onRecordChange = undefined
thisObject.isVisible = undefined
currentRecord = undefined
lastRecord = undefined
upDownButton = undefined
thisObject.assetBalances.finalize()
thisObject.assetBalances = undefined
}
function getContainer(point) {
if (thisObject.isVisible !== true) { return }
let container;
container = upDownButton.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 onRecordChange(records) {
currentRecord = records.currentRecord;
lastRecord = records.lastRecord
}
function draw() {
if (thisObject.isVisible !== true) { return }
thisObject.container.frame.draw(false, false, true, thisObject.fitFunction);
plotCurrentRecordInfo();
upDownButton.draw()
/* Define panel name */
if (thisObject.session !== undefined) {
const MAX_LABEL_LENGTH = 25
if (thisObject.session.name.length > MAX_LABEL_LENGTH) {
container.frame.containerName = thisObject.session.name.substring(0, MAX_LABEL_LENGTH) + '...'
} else {
container.frame.containerName = thisObject.session.name
}
}
}
function plotCurrentRecordInfo() {
if (currentRecord === 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 */
let y = 0;
let increment = 0.024 / HEIGHT_FACTOR * 2.5;
y = y + increment;
y = y + increment;
printLabel('Asset Balances', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
/* Parameters */
let params
let paramsArray = []
let positionTaken = false
if (currentRecord.positionSize > 0) {
positionTaken = true
}
let testPoint = {
x: 0,
y: thisObject.container.frame.height
}
testPoint = thisObject.container.frame.frameThisPoint(testPoint)
let fitPoint = thisObject.fitFunction(testPoint)
if (fitPoint.y !== testPoint.y) {
return
}
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 = currentRecord.baseAsset
params.LEFT_OFFSET = X_AXIS
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 = currentRecord.quotedAsset
params.LEFT_OFFSET = X_AXIS
params.POSITION_TAKEN = positionTaken
params.BASE_ASSET = currentRecord.baseAsset
params.DECIMALS = 2
paramsArray.push(params)
thisObject.assetBalances.setParamsArray(paramsArray)
thisObject.assetBalances.draw()
}
}
@@ -0,0 +1,178 @@
function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimulationCurrentPositionPanel() {
let thisObject = {
fitFunction: undefined,
onRecordChange: onRecordChange,
container: undefined,
session: undefined,
isVisible: true,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
};
let container = newContainer();
container.initialize();
thisObject.container = container;
container.frame.containerName = "Simulation Current Position Panel";
let currentRecord;
let lastRecord;
let upDownButton
const HEIGHT_FACTOR = 1.25
return thisObject;
function initialize() {
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL * 1;
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL * HEIGHT_FACTOR;
thisObject.container.frame.position.x = canvas.chartingSpace.viewport.visibleArea.topRight.x - thisObject.container.frame.width * 1;
thisObject.container.frame.position.y = canvas.chartingSpace.viewport.visibleArea.topRight.y;
upDownButton = newUpDownButton()
upDownButton.parentContainer = thisObject.container
upDownButton.container.frame.parentFrame = thisObject.container.frame
upDownButton.fitFunction = thisObject.fitFunction
upDownButton.initialize()
}
function finalize() {
thisObject.session = undefined
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.onRecordChange = undefined
thisObject.isVisible = undefined
currentRecord = undefined
lastRecord = undefined
upDownButton = undefined
}
function getContainer(point) {
if (thisObject.isVisible !== true) { return }
let container;
container = upDownButton.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 onRecordChange(records) {
currentRecord = records.currentRecord;
lastRecord = records.lastRecord
}
function draw() {
if (thisObject.isVisible !== true) { return }
thisObject.container.frame.draw(false, false, true, thisObject.fitFunction);
plotCurrentRecordInfo();
upDownButton.draw()
/* Define panel name */
if (thisObject.session !== undefined) {
const MAX_LABEL_LENGTH = 25
if (thisObject.session.name.length > MAX_LABEL_LENGTH) {
container.frame.containerName = thisObject.session.name.substring(0, MAX_LABEL_LENGTH) + '...'
} else {
container.frame.containerName = thisObject.session.name
}
}
}
function plotCurrentRecordInfo() {
if (currentRecord === 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 */
let y = 0;
let increment = 0.024 / HEIGHT_FACTOR * 2.5;
y = y + increment;
y = y + increment;
printLabel('Current Position', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1.00', 14, undefined, true, thisObject.container, thisObject.fitFunction);
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);
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);
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);
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);
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);
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);
y = y + increment;
y = y + increment;
printLabel('Latest Position', 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.lastTradeProfitLoss), 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);
}
}
@@ -0,0 +1,177 @@
function newTradingEnginesPlottersTradingSimulationTradingSimulationTradingSimulationPartialResultsPanel() {
let thisObject = {
fitFunction: undefined,
onRecordChange: onRecordChange,
container: undefined,
session: undefined,
isVisible: true,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
};
let container = newContainer();
container.initialize();
thisObject.container = container;
container.frame.containerName = "Simulation Partial Results Panel";
let currentRecord;
let lastRecord;
let upDownButton
const HEIGHT_FACTOR = 1.25
return thisObject;
function initialize() {
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL * 1;
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL * HEIGHT_FACTOR;
thisObject.container.frame.position.x = canvas.chartingSpace.viewport.visibleArea.topRight.x - thisObject.container.frame.width * 1;
thisObject.container.frame.position.y = canvas.chartingSpace.viewport.visibleArea.topRight.y;
upDownButton = newUpDownButton()
upDownButton.parentContainer = thisObject.container
upDownButton.container.frame.parentFrame = thisObject.container.frame
upDownButton.fitFunction = thisObject.fitFunction
upDownButton.initialize()
}
function finalize() {
thisObject.session = undefined
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.onRecordChange = undefined
thisObject.isVisible = undefined
currentRecord = undefined
lastRecord = undefined
upDownButton = undefined
}
function getContainer(point) {
if (thisObject.isVisible !== true) { return }
let container;
container = upDownButton.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 onRecordChange(records) {
currentRecord = records.currentRecord;
lastRecord = records.lastRecord
}
function draw() {
if (thisObject.isVisible !== true) { return }
thisObject.container.frame.draw(false, false, true, thisObject.fitFunction);
plotCurrentRecordInfo();
upDownButton.draw()
/* Define panel name */
if (thisObject.session !== undefined) {
const MAX_LABEL_LENGTH = 25
if (thisObject.session.name.length > MAX_LABEL_LENGTH) {
container.frame.containerName = thisObject.session.name.substring(0, MAX_LABEL_LENGTH) + '...'
} else {
container.frame.containerName = thisObject.session.name
}
}
}
function plotCurrentRecordInfo() {
if (currentRecord === 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 */
let y = 0;
let increment = 0.024 / HEIGHT_FACTOR * 2.5;
y = y + increment;
y = y + increment;
printLabel('Partial Results', 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);
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);
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);
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);
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);
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);
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);
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);
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);
}
}
@@ -0,0 +1,56 @@
{
"displayName": "Plotters Trading Simulation",
"codeName": "PlottersTradingSimulation",
"dataMine": "Masters",
"modules": [
{
"codeName": "TradingSimulation",
"moduleName": "TradingSimulation",
"description": "Plots Bollinger Records.",
"profilePicture": "TradingSimulation.png",
"panels": [
{
"codeName": "TradingSimulationPanel",
"moduleName": "TradingSimulationPanel",
"event": "Current Record Changed"
}
]
},
{
"codeName": "Conditions",
"moduleName": "Conditions",
"description": "Plots Simulation Conditions.",
"profilePicture": "Conditions.png",
"panels": []
},
{
"codeName": "Strategies",
"moduleName": "Strategies",
"description": "Plots Strategies.",
"profilePicture": "Strategies.png",
"panels": [
]
},
{
"codeName": "Trades",
"moduleName": "Trades",
"description": "Plots Trades.",
"profilePicture": "Trades.png",
"panels": [
]
},
{
"codeName": "SimulationExecution",
"moduleName": "SimulationExecution",
"description": "Plots Simulation Execution.",
"profilePicture": "SimulationExecution.png",
"panels": [
{
"codeName": "SimulationExecutionPanel",
"moduleName": "SimulationExecutionPanel",
"event": "Current Record Changed"
}
]
}
]
}
+16 -8
View File
@@ -5,7 +5,8 @@ exports.newFileStorage = function newFileStorage(logger) {
const MODULE_NAME = 'FileStorage'
const MAX_RETRY = 30
const RETRY_TIME_IN_MILISECONDS = 250
const FAST_RETRY_TIME_IN_MILISECONDS = 500
const SLOW_RETRY_TIME_IN_MILISECONDS = 5000
let currentRetryGetTextFile = 0
let currentRetryWriteTextFile = 0
let currentRetryDeleteTextFile = 0
@@ -49,7 +50,10 @@ exports.newFileStorage = function newFileStorage(logger) {
fs.readFile(fileLocation, onFileRead)
function onFileRead(err, text) {
let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS
if (currentRetryGetTextFile < MAX_RETRY - 3) {
retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS
}
if (err) {
if (err.code === 'ENOENT') { // since files are deleted before being replaced, it can happen that it does not exist and after a retry it does.
@@ -64,7 +68,7 @@ exports.newFileStorage = function newFileStorage(logger) {
} else {
fileDoesNotExist = true
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Retrying. ')
setTimeout(retry, RETRY_TIME_IN_MILISECONDS)
setTimeout(retry, retryTimeToUse)
return
}
}
@@ -72,13 +76,13 @@ exports.newFileStorage = function newFileStorage(logger) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> err = ' + err.stack)
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> filePath = ' + filePath)
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> err = ' + err.stack)
setTimeout(retry, RETRY_TIME_IN_MILISECONDS)
setTimeout(retry, retryTimeToUse)
return
}
if (text.toString() === "") {
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Read and Empty File -> filePath = ' + filePath)
setTimeout(retry, RETRY_TIME_IN_MILISECONDS)
setTimeout(retry, retryTimeToUse)
return
}
@@ -145,10 +149,14 @@ exports.newFileStorage = function newFileStorage(logger) {
fs.writeFile(fileLocation + '.tmp', fileContent, onFileWritenn)
function onFileWritenn(err) {
let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS
if (currentRetryWriteTextFile < MAX_RETRY - 3) {
retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS
}
if (err) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> Error writing file -> file = ' + fileLocation)
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> Error writing file -> err = ' + err.stack)
setTimeout(retry, RETRY_TIME_IN_MILISECONDS)
setTimeout(retry, retryTimeToUse)
} else {
const fs = require('fs')
@@ -162,7 +170,7 @@ exports.newFileStorage = function newFileStorage(logger) {
if (code !== '' && code !== 'ENOENT') {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error renaming file -> file = ' + fileLocation)
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error renaming file -> err = ' + err.stack)
setTimeout(retry, RETRY_TIME_IN_MILISECONDS)
setTimeout(retry, retryTimeToUse)
} else {
const fs = require('fs')
@@ -172,7 +180,7 @@ exports.newFileStorage = function newFileStorage(logger) {
if (err) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onRenamed -> Error renaming file -> file = ' + fileLocation + '.tmp')
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onRenamed -> Error renaming file -> err = ' + err.stack)
setTimeout(retry, RETRY_TIME_IN_MILISECONDS)
setTimeout(retry, retryTimeToUse)
} else {
callBackFunction(global.DEFAULT_OK_RESPONSE)
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

+9 -9
View File
@@ -181,15 +181,15 @@ function newAppLoader() {
'Plotters/Masters/Plotters-Bollinger-Bands/BollingerBands.js',
'Plotters/Masters/Plotters-Bollinger-Bands/BollingerBandsPanel.js',
'Plotters/Masters/Plotters-Bollinger-Bands/PercentageBandwidth.js',
'Plotters/Masters/Plotters-Trading-Simulation/TradingSimulation.js',
'Plotters/Masters/Plotters-Trading-Simulation/TradingSimulationAssetBalancesPanel.js',
'Plotters/Masters/Plotters-Trading-Simulation/TradingSimulationCurrentPositionPanel.js',
'Plotters/Masters/Plotters-Trading-Simulation/TradingSimulationPartialResultsPanel.js',
'Plotters/Masters/Plotters-Trading-Simulation/Conditions.js',
'Plotters/Masters/Plotters-Trading-Simulation/Strategies.js',
'Plotters/Masters/Plotters-Trading-Simulation/Trades.js',
'Plotters/Masters/Plotters-Trading-Simulation/SimulationExecution.js',
'Plotters/Masters/Plotters-Trading-Simulation/SimulationExecutionPanel.js'
'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/Conditions.js',
'Plotters/TradingEngines/Plotters-Trading-Simulation/Strategies.js',
'Plotters/TradingEngines/Plotters-Trading-Simulation/Trades.js',
'Plotters/TradingEngines/Plotters-Trading-Simulation/SimulationExecution.js',
'Plotters/TradingEngines/Plotters-Trading-Simulation/SimulationExecutionPanel.js'
]
}
+1 -1
View File
@@ -1 +1 @@
{"type":"Workspace","name":"My Workspace","rootNodes":[{"type":"Network","name":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","dataStorage":{"type":"Data Storage","name":"New Data Storage","sessionIndependentData":{"type":"Session Independent Data","name":"New Session Independent Data","exchangeDataProducts":[{"type":"Exchange Data Products","name":"Bittrex","singleMarketData":[{"type":"Single Market Data","name":"Bittrex DASH/BTC","dataProducts":[{"type":"Data Product","name":"Candles","id":"da2a0759-35a8-48a9-96e0-774212d4be70","savedPayload":{"position":{"x":40547.50864374642,"y":29458.159568577485},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Candles","id":"fe6065ec-4d2d-47a0-bae0-8647f0e195d7"}}},{"type":"Data Product","name":"Volumes","id":"2e38ef30-9cd1-40ad-82b4-ce8f70b53e47","savedPayload":{"position":{"x":40421.73265277628,"y":29446.388474093364},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Volumes","id":"1a366aef-efef-470e-88e0-2a6fbe4dd91f"}}},{"type":"Data Product","name":"Candle-Stairs","id":"8af5800d-5ade-49a6-b88e-291ad2c7fcb6","savedPayload":{"position":{"x":40301.14133183628,"y":29408.85317326678},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Candle-Stairs","id":"642474e9-da61-4168-97dc-7f7869bebc02"}}},{"type":"Data Product","name":"Volume-Stairs","id":"7805c1c9-d30e-41d9-baab-e34ac28dd6f9","savedPayload":{"position":{"x":40187.396275814746,"y":29353.016112581576},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Volume-Stairs","id":"846e9572-c4d6-4c7e-942e-c82402c5ecea"}}},{"type":"Data Product","name":"Bollinger Bands","id":"3f4f3bce-51ff-4290-a6b7-3227d5455c20","savedPayload":{"position":{"x":40096.481080845784,"y":29265.09743042856},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Bollinger Bands","id":"29088877-8d63-4217-8d34-8742afc262f4"}}},{"type":"Data Product","name":"Percentage Bandwidth","id":"8f76b5f3-16ce-490b-9f7c-c0c8ae183785","savedPayload":{"position":{"x":40012.72356856686,"y":29171.40183064097},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Percentage Bandwidth","id":"3b7885a0-cd72-4a3f-a38b-3dc8c47bd068"}}},{"type":"Data Product","name":"Bollinger Channels Objects","id":"1c0d2573-2818-45bb-ab65-3b31222c0556","savedPayload":{"position":{"x":39948.363007140084,"y":29062.244116046924},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Bollinger Channels Objects","id":"1f111f72-624f-4166-9f99-ab8d785d5267"}}},{"type":"Data Product","name":"Bollinger Sub-Channels Objects","id":"871e1f89-a659-4974-9929-5e5d2e43a09b","savedPayload":{"position":{"x":39912.69159220981,"y":28940.34283010204},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Bollinger Sub-Channels Objects","id":"080c87fc-4546-4482-ab11-180a33f6d9ab"}}},{"type":"Data Product","name":"Popular SMAs","id":"55497f8b-b1d8-4eba-acb1-90f0a8b228f9","savedPayload":{"position":{"x":39896.003039224,"y":28814.06986752792},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Popular SMAs","id":"4029d5bf-a8ad-4d80-b874-2af506e0ab34"}}},{"type":"Data Product","name":"Base7 SMAs","id":"2271f823-268e-4042-966b-cd5b5cf2e009","savedPayload":{"position":{"x":39919.361557320895,"y":28689.123643504383},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinnLine truncated
{"type":"Workspace","name":"My Workspace","rootNodes":[{"type":"Network","name":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","dataStorage":{"type":"Data Storage","name":"New Data Storage","sessionIndependentData":{"type":"Session Independent Data","name":"New Session Independent Data","exchangeDataProducts":[{"type":"Exchange Data Products","name":"Binance","singleMarketData":[{"type":"Single Market Data","name":"Binance BTC/USDT","dataProducts":[{"type":"Data Product","name":"Candles","id":"884a5d08-b607-4b2b-8e7a-8adeb7e8dd4a","savedPayload":{"position":{"x":40547.50864374642,"y":29458.159568577485},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Candles","id":"fe6065ec-4d2d-47a0-bae0-8647f0e195d7"}}},{"type":"Data Product","name":"Volumes","id":"4ec71a01-3d83-4e8e-9780-bcb700dcf66a","savedPayload":{"position":{"x":40421.73265277628,"y":29446.388474093364},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Volumes","id":"1a366aef-efef-470e-88e0-2a6fbe4dd91f"}}},{"type":"Data Product","name":"Candle-Stairs","id":"5979844b-35e7-4c04-938f-18e6156352a0","savedPayload":{"position":{"x":40301.14133183628,"y":29408.85317326678},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Candle-Stairs","id":"642474e9-da61-4168-97dc-7f7869bebc02"}}},{"type":"Data Product","name":"Volume-Stairs","id":"dd1f89bc-3c2f-4fc4-a5f1-de7a34e0997e","savedPayload":{"position":{"x":40187.396275814746,"y":29353.016112581576},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Volume-Stairs","id":"846e9572-c4d6-4c7e-942e-c82402c5ecea"}}},{"type":"Data Product","name":"Bollinger Bands","id":"68df01d8-d9a8-400c-aa76-8da44c5dc040","savedPayload":{"position":{"x":40096.481080845784,"y":29265.09743042856},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Bollinger Bands","id":"29088877-8d63-4217-8d34-8742afc262f4"}}},{"type":"Data Product","name":"Percentage Bandwidth","id":"9b5b1b81-c68c-45a5-8123-1a114a24b744","savedPayload":{"position":{"x":40012.72356856686,"y":29171.40183064097},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Percentage Bandwidth","id":"3b7885a0-cd72-4a3f-a38b-3dc8c47bd068"}}},{"type":"Data Product","name":"Bollinger Channels Objects","id":"632f0f98-eb2c-4820-9943-662a4903be81","savedPayload":{"position":{"x":39948.363007140084,"y":29062.244116046924},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Bollinger Channels Objects","id":"1f111f72-624f-4166-9f99-ab8d785d5267"}}},{"type":"Data Product","name":"Bollinger Sub-Channels Objects","id":"88a1ca81-b317-4ab2-b651-c8fa566e8e28","savedPayload":{"position":{"x":39912.69159220981,"y":28940.34283010204},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Bollinger Sub-Channels Objects","id":"080c87fc-4546-4482-ab11-180a33f6d9ab"}}},{"type":"Data Product","name":"Popular SMAs","id":"5bce195f-7d08-4281-bb9d-ca1e9417068e","savedPayload":{"position":{"x":39896.003039224,"y":28814.06986752792},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3},"uiObject":{},"referenceParent":{"type":"Product Definition","name":"Popular SMAs","id":"4029d5bf-a8ad-4d80-b874-2af506e0ab34"}}},{"type":"Data Product","name":"Base7 SMAs","id":"b9145946-1899-4fac-b531-47ed600873be","savedPayload":{"position":{"x":39919.361557320895,"y":28689.123643504383},"targetPosition":{"x":40547.50864374642,"y":28814.06986752792},"floatingObject":{"isPinnLine truncated