Current Folder
This commit is contained in:
1 parent
8b3382289b
commit
cfcada880d
4379 files changed
No files matched your search
@@ -1,726 +0,0 @@
|
||||
function newMastersPlottersBollingerBandsBollingerBands() {
|
||||
|
||||
const MODULE_NAME = "Bands 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.
|
||||
|
||||
currentBand: 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 bands = []; // Here we keep the bands to be ploted every time the Draw() function is called by the AAWebPlatform.
|
||||
|
||||
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)
|
||||
UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.stopListening(zoomChangedEventSubscriptionId);
|
||||
UI.projects.superalgos.spaces.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 {
|
||||
|
||||
/* 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 = UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.listenToEvent("Zoom Changed", onViewportZoomChanged);
|
||||
offsetChangedEventSubscriptionId = UI.projects.superalgos.spaces.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();
|
||||
|
||||
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 = UI.projects.superalgos.utilities.dateRateTransformations.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] 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) {
|
||||
|
||||
let newMarketFile = marketFiles.getFile(pTimeFrame);
|
||||
|
||||
if (newMarketFile !== undefined) {
|
||||
|
||||
marketFile = newMarketFile;
|
||||
recalculate();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
let newFileCursor = dailyFiles.getFileCursor(pTimeFrame);
|
||||
|
||||
if (newFileCursor !== undefined) {
|
||||
|
||||
fileCursor = newFileCursor;
|
||||
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 {
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
plotChart();
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] draw -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function recalculate() {
|
||||
|
||||
try {
|
||||
|
||||
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
|
||||
|
||||
recalculateUsingMarketFiles();
|
||||
|
||||
} else {
|
||||
|
||||
recalculateUsingDailyFiles();
|
||||
|
||||
}
|
||||
|
||||
thisObject.container.eventHandler.raiseEvent("Bands Changed", bands);
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] recalculate -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateUsingDailyFiles() {
|
||||
|
||||
try {
|
||||
|
||||
if (fileCursor === undefined) { return; } // We need to wait
|
||||
|
||||
if (fileCursor.files.size === 0) { return; } // We need to wait until there are files in the cursor
|
||||
|
||||
let daysOnSides = getSideDays(timeFrame);
|
||||
|
||||
let leftDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
|
||||
let rightDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.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());
|
||||
|
||||
bands = [];
|
||||
let lastBand
|
||||
|
||||
while (currentDate.valueOf() <= farRightDate.valueOf() + ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
let stringDate = currentDate.getUTCFullYear() + '-' + pad(currentDate.getUTCMonth() + 1, 2) + '-' + pad(currentDate.getUTCDate(), 2);
|
||||
|
||||
let dailyFile = fileCursor.files.get(stringDate);
|
||||
|
||||
if (dailyFile !== undefined) {
|
||||
|
||||
for (let i = 0; i < dailyFile.length; i++) {
|
||||
|
||||
let band = {
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
movingAverage: undefined,
|
||||
standardDeviation: undefined,
|
||||
deviation: undefined
|
||||
};
|
||||
|
||||
band.begin = dailyFile[i][0];
|
||||
band.end = dailyFile[i][1];
|
||||
band.movingAverage = dailyFile[i][2];
|
||||
band.standardDeviation = dailyFile[i][3];
|
||||
band.deviation = dailyFile[i][4];
|
||||
|
||||
if (lastBand !== undefined) {
|
||||
if (lastBand.movingAverage > band.movingAverage) { band.direction = "Down" }
|
||||
if (lastBand.movingAverage < band.movingAverage) { band.direction = "Up" }
|
||||
if (lastBand.movingAverage === band.movingAverage) { band.direction = "Side" }
|
||||
}
|
||||
|
||||
lastBand = band
|
||||
|
||||
if (
|
||||
(band.begin >= farLeftDate.valueOf() && band.end <= farRightDate.valueOf()) &&
|
||||
(band.begin >= coordinateSystem.min.x && band.end <= coordinateSystem.max.x)
|
||||
) {
|
||||
|
||||
bands.push(band);
|
||||
|
||||
if (datetime.valueOf() >= band.begin && datetime.valueOf() <= band.end) {
|
||||
|
||||
thisObject.currentBand = band;
|
||||
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.currentBand);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS);
|
||||
}
|
||||
|
||||
/* Lests check if all the visible screen is going to be covered by bands. */
|
||||
|
||||
let lowerEnd = leftDate.valueOf();
|
||||
let upperEnd = rightDate.valueOf();
|
||||
|
||||
if (bands.length > 0) {
|
||||
|
||||
if (bands[0].begin > lowerEnd || bands[bands.length - 1].end < upperEnd) {
|
||||
|
||||
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 = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
|
||||
let rightDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.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);
|
||||
|
||||
bands = [];
|
||||
let lastBand
|
||||
|
||||
for (let i = 0; i < marketFile.length; i++) {
|
||||
|
||||
let band = {
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
movingAverage: undefined,
|
||||
standardDeviation: undefined,
|
||||
deviation: undefined
|
||||
};
|
||||
|
||||
band.begin = marketFile[i][0];
|
||||
band.end = marketFile[i][1];
|
||||
band.movingAverage = marketFile[i][2];
|
||||
band.standardDeviation = marketFile[i][3];
|
||||
band.deviation = marketFile[i][4];
|
||||
|
||||
if (lastBand !== undefined) {
|
||||
if (lastBand.movingAverage > band.movingAverage) { band.direction = "Down" }
|
||||
if (lastBand.movingAverage < band.movingAverage) { band.direction = "Up" }
|
||||
if (lastBand.movingAverage === band.movingAverage) { band.direction = "Side" }
|
||||
}
|
||||
|
||||
lastBand = band
|
||||
|
||||
if (
|
||||
(band.begin >= leftDate.valueOf() && band.end <= rightDate.valueOf()) &&
|
||||
(band.begin >= coordinateSystem.min.x && band.end <= coordinateSystem.max.x)
|
||||
) {
|
||||
|
||||
bands.push(band);
|
||||
|
||||
if (datetime.valueOf() >= band.begin && datetime.valueOf() <= band.end) {
|
||||
|
||||
thisObject.currentBand = band;
|
||||
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.currentBand);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingMarketFiles -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function plotChart() {
|
||||
|
||||
try {
|
||||
|
||||
let band;
|
||||
let previousBand;
|
||||
|
||||
if (bands.length > 0) {
|
||||
|
||||
/* Now we calculate and plot the bands */
|
||||
|
||||
for (let i = 1; i < bands.length; i++) {
|
||||
|
||||
band = bands[i];
|
||||
previousBand = bands[i - 1];
|
||||
|
||||
/* From here we draw the actual Bollinger Bands and lines it contains. */
|
||||
|
||||
let bandPoint1 = {
|
||||
x: band.begin,
|
||||
y: previousBand.movingAverage - previousBand.deviation
|
||||
};
|
||||
|
||||
let bandPoint2 = {
|
||||
x: band.begin,
|
||||
y: previousBand.movingAverage + previousBand.deviation
|
||||
};
|
||||
|
||||
let bandPoint3 = {
|
||||
x: band.end,
|
||||
y: band.movingAverage + band.deviation
|
||||
};
|
||||
|
||||
let bandPoint4 = {
|
||||
x: band.end,
|
||||
y: band.movingAverage - band.deviation
|
||||
};
|
||||
|
||||
let bandPoint5 = {
|
||||
x: band.begin,
|
||||
y: previousBand.movingAverage
|
||||
};
|
||||
|
||||
let bandPoint6 = {
|
||||
x: band.end,
|
||||
y: band.movingAverage
|
||||
};
|
||||
|
||||
bandPoint1 = coordinateSystem.transformThisPoint(bandPoint1);
|
||||
bandPoint2 = coordinateSystem.transformThisPoint(bandPoint2);
|
||||
bandPoint3 = coordinateSystem.transformThisPoint(bandPoint3);
|
||||
bandPoint4 = coordinateSystem.transformThisPoint(bandPoint4);
|
||||
bandPoint5 = coordinateSystem.transformThisPoint(bandPoint5);
|
||||
bandPoint6 = coordinateSystem.transformThisPoint(bandPoint6);
|
||||
|
||||
bandPoint1 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(bandPoint1, thisObject.container);
|
||||
bandPoint2 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(bandPoint2, thisObject.container);
|
||||
bandPoint3 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(bandPoint3, thisObject.container);
|
||||
bandPoint4 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(bandPoint4, thisObject.container);
|
||||
bandPoint5 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(bandPoint5, thisObject.container);
|
||||
bandPoint6 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(bandPoint6, thisObject.container);
|
||||
|
||||
if (bandPoint2.x < UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.x || bandPoint1.x > UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (UI.projects.superalgos.spaces.chartingSpace.viewport.zoomTargetLevel < UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_PACKING_OBJECTS_AT_THE_BOTTOM_OR_TOP_OF_VIEWPORT) {
|
||||
let diffA = bandPoint1.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.y
|
||||
if (diffA > 0) {
|
||||
bandPoint1.y = bandPoint1.y - diffA
|
||||
bandPoint2.y = bandPoint2.y - diffA
|
||||
bandPoint3.y = bandPoint3.y - diffA
|
||||
bandPoint4.y = bandPoint4.y - diffA
|
||||
bandPoint5.y = bandPoint5.y - diffA
|
||||
bandPoint6.y = bandPoint6.y - diffA
|
||||
}
|
||||
|
||||
let diffB = bandPoint2.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.y
|
||||
if (diffB < 0) {
|
||||
bandPoint1.y = bandPoint1.y - diffB
|
||||
bandPoint2.y = bandPoint2.y - diffB
|
||||
bandPoint3.y = bandPoint3.y - diffB
|
||||
bandPoint4.y = bandPoint4.y - diffB
|
||||
bandPoint5.y = bandPoint5.y - diffB
|
||||
bandPoint6.y = bandPoint6.y - diffB
|
||||
}
|
||||
}
|
||||
|
||||
bandPoint1 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(bandPoint1);
|
||||
bandPoint2 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(bandPoint2);
|
||||
bandPoint3 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(bandPoint3);
|
||||
bandPoint4 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(bandPoint4);
|
||||
bandPoint5 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(bandPoint5);
|
||||
bandPoint6 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(bandPoint6);
|
||||
|
||||
bandPoint1 = thisObject.fitFunction(bandPoint1);
|
||||
bandPoint2 = thisObject.fitFunction(bandPoint2);
|
||||
bandPoint3 = thisObject.fitFunction(bandPoint3);
|
||||
bandPoint4 = thisObject.fitFunction(bandPoint4);
|
||||
bandPoint5 = thisObject.fitFunction(bandPoint5);
|
||||
bandPoint6 = thisObject.fitFunction(bandPoint6);
|
||||
|
||||
/* First we are drawing a semi-transparent background */
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(bandPoint1.x, bandPoint1.y);
|
||||
browserCanvasContext.lineTo(bandPoint2.x, bandPoint2.y);
|
||||
browserCanvasContext.lineTo(bandPoint3.x, bandPoint3.y);
|
||||
browserCanvasContext.lineTo(bandPoint4.x, bandPoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', 0.05)';
|
||||
|
||||
if (userPositionDate >= band.begin && userPositionDate <= band.end) {
|
||||
/* highlight the current band */
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 0.05)'; // Current band accroding to time
|
||||
}
|
||||
|
||||
if (
|
||||
bandPoint1.x < UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.x + 150
|
||||
||
|
||||
bandPoint1.x > UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.x - 150
|
||||
) {
|
||||
// we leave this bands without fill.
|
||||
} else {
|
||||
browserCanvasContext.fill();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Next we are drawing the outter bands lines */
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(bandPoint1.x, bandPoint1.y);
|
||||
browserCanvasContext.lineTo(bandPoint4.x, bandPoint4.y);
|
||||
browserCanvasContext.moveTo(bandPoint2.x, bandPoint2.y);
|
||||
browserCanvasContext.lineTo(bandPoint3.x, bandPoint3.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', 1)';
|
||||
|
||||
if (userPositionDate >= band.begin && userPositionDate <= band.end) {
|
||||
|
||||
/* highlight the current band */
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)'; // Current band accroding to time
|
||||
|
||||
let currentBand = {
|
||||
bodyWidth: bandPoint3.x - bandPoint2.x,
|
||||
leftBodyHeight: bandPoint2.y - bandPoint1.y,
|
||||
rightBodyHeight: bandPoint3.y - bandPoint4.y,
|
||||
topDelta: bandPoint3.y - bandPoint2.y,
|
||||
bottomDelta: bandPoint4.y - bandPoint1.y,
|
||||
period: timeFrame,
|
||||
innerBand: band
|
||||
};
|
||||
|
||||
thisObject.container.eventHandler.raiseEvent("Current Record Changed", currentBand);
|
||||
}
|
||||
|
||||
browserCanvasContext.lineWidth = 0.2;
|
||||
browserCanvasContext.setLineDash([0, 0])
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
|
||||
|
||||
/* Finally we draw the moving average line */
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(bandPoint5.x, bandPoint5.y);
|
||||
browserCanvasContext.lineTo(bandPoint6.x, bandPoint6.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (bandPoint5.y > bandPoint6.y) {
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', 1)';
|
||||
} else {
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', 1)';
|
||||
}
|
||||
|
||||
if (userPositionDate >= band.begin && userPositionDate <= band.end) {
|
||||
/* highlight the current band */
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)'; // Current band accroding to time
|
||||
}
|
||||
|
||||
browserCanvasContext.lineWidth = 0.2;
|
||||
browserCanvasContext.setLineDash([0, 0])
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
/* Contributing to Auto-Scale*/
|
||||
coordinateSystem.reportYValue(band.movingAverage + band.deviation)
|
||||
coordinateSystem.reportYValue(band.movingAverage - band.deviation)
|
||||
}
|
||||
}
|
||||
|
||||
} 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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
|
||||
function newMastersPlottersBollingerBandsBollingerBandsBollingerBandsPanel() {
|
||||
|
||||
var thisObject = {
|
||||
fitFunction: undefined,
|
||||
onRecordChange: onRecordChange,
|
||||
container: undefined,
|
||||
isVisible: true,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
};
|
||||
|
||||
thisObject.container = newContainer();
|
||||
thisObject.container.initialize();
|
||||
thisObject.container.frame.containerName = "Bollinger Band";
|
||||
|
||||
let currentBand;
|
||||
let upDownButton
|
||||
|
||||
return thisObject;
|
||||
|
||||
function finalize() {
|
||||
thisObject.container.finalize()
|
||||
thisObject.container = undefined
|
||||
thisObject.fitFunction = undefined
|
||||
thisObject.isVisible = undefined
|
||||
|
||||
currentBand = undefined
|
||||
upDownButton.finalize()
|
||||
upDownButton = undefined
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL;
|
||||
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL;
|
||||
|
||||
thisObject.container.frame.position.x = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight.x - thisObject.container.frame.width * 3;
|
||||
thisObject.container.frame.position.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.y - thisObject.container.frame.height;
|
||||
|
||||
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(lastCurrentBand) {
|
||||
|
||||
currentBand = lastCurrentBand;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function draw() {
|
||||
if (thisObject.isVisible !== true) { return }
|
||||
thisObject.container.frame.draw(false, false, true, thisObject.fitFunction);
|
||||
|
||||
plotCurrentBandInfo();
|
||||
|
||||
upDownButton.draw()
|
||||
}
|
||||
|
||||
|
||||
function plotCurrentBandInfo() {
|
||||
|
||||
if (currentBand === undefined) { return; }
|
||||
if (currentBand.innerBand === 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;
|
||||
|
||||
var bandPoint1 = {
|
||||
x: X_AXIS - currentBand.bodyWidth / 2,
|
||||
y: Y_AXIS - currentBand.leftBodyHeight / 2 - currentBand.bottomDelta / 4
|
||||
};
|
||||
|
||||
var bandPoint2 = {
|
||||
x: X_AXIS - currentBand.bodyWidth / 2,
|
||||
y: Y_AXIS + currentBand.leftBodyHeight / 2 - currentBand.topDelta / 4
|
||||
};
|
||||
|
||||
var bandPoint3 = {
|
||||
x: X_AXIS + currentBand.bodyWidth / 2,
|
||||
y: Y_AXIS + currentBand.rightBodyHeight / 2 + currentBand.topDelta / 4
|
||||
};
|
||||
|
||||
var bandPoint4 = {
|
||||
x: X_AXIS + currentBand.bodyWidth / 2,
|
||||
y: Y_AXIS - currentBand.rightBodyHeight / 2 + currentBand.bottomDelta / 4
|
||||
};
|
||||
|
||||
/* Extra bounderies due to constrained space */
|
||||
|
||||
const upperLimit = frameTitleHeight + frameBodyHeight * 0.25;
|
||||
const downLimit = frameTitleHeight + frameBodyHeight * 0.75;
|
||||
|
||||
if (bandPoint1.y > downLimit) { bandPoint1.y = downLimit; }
|
||||
if (bandPoint4.y > downLimit) { bandPoint4.y = downLimit; }
|
||||
|
||||
if (bandPoint2.y < upperLimit) { bandPoint2.y = upperLimit; }
|
||||
if (bandPoint3.y < upperLimit) { bandPoint3.y = upperLimit; }
|
||||
|
||||
const leftLimit = thisObject.container.frame.width * 0.40;
|
||||
const rightLimit = thisObject.container.frame.width * 0.60;
|
||||
|
||||
if (bandPoint1.x < leftLimit) { bandPoint1.x = leftLimit; }
|
||||
if (bandPoint2.x < leftLimit) { bandPoint2.x = leftLimit; }
|
||||
|
||||
if (bandPoint3.x > rightLimit) { bandPoint3.x = rightLimit; }
|
||||
if (bandPoint4.x > rightLimit) { bandPoint4.x = rightLimit; }
|
||||
|
||||
bandPoint1 = thisObject.container.frame.frameThisPoint(bandPoint1);
|
||||
bandPoint2 = thisObject.container.frame.frameThisPoint(bandPoint2);
|
||||
bandPoint3 = thisObject.container.frame.frameThisPoint(bandPoint3);
|
||||
bandPoint4 = thisObject.container.frame.frameThisPoint(bandPoint4);
|
||||
|
||||
bandPoint1 = thisObject.fitFunction(bandPoint1)
|
||||
bandPoint2 = thisObject.fitFunction(bandPoint2)
|
||||
bandPoint3 = thisObject.fitFunction(bandPoint3)
|
||||
bandPoint4 = thisObject.fitFunction(bandPoint4)
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(bandPoint1.x, bandPoint1.y);
|
||||
browserCanvasContext.lineTo(bandPoint2.x, bandPoint2.y);
|
||||
browserCanvasContext.lineTo(bandPoint3.x, bandPoint3.y);
|
||||
browserCanvasContext.lineTo(bandPoint4.x, bandPoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
const OPACITY = '0.1';
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + OPACITY + ')';
|
||||
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(bandPoint1.x, bandPoint1.y);
|
||||
browserCanvasContext.lineTo(bandPoint4.x, bandPoint4.y);
|
||||
browserCanvasContext.moveTo(bandPoint2.x, bandPoint2.y);
|
||||
browserCanvasContext.lineTo(bandPoint3.x, bandPoint3.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', 1)';
|
||||
|
||||
browserCanvasContext.lineWidth = 0.2;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
let y1 = bandPoint1.y + (bandPoint2.y - bandPoint1.y) / 2;
|
||||
let y2 = bandPoint4.y - (bandPoint4.y - bandPoint3.y) / 2;
|
||||
|
||||
browserCanvasContext.moveTo(bandPoint1.x, y1);
|
||||
browserCanvasContext.lineTo(bandPoint4.x, y2);
|
||||
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (y1 > y2) {
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', 1)';
|
||||
} else {
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', 1)';
|
||||
}
|
||||
|
||||
browserCanvasContext.lineWidth = 0.2;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
/* put the labels with the bands values */
|
||||
|
||||
let y;
|
||||
|
||||
if (currentBand.innerBand.direction !== undefined) {
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel('Direction', undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.05, '0.60', undefined, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel(currentBand.innerBand.direction, undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.10, '1.00', 15, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
}
|
||||
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel('Moving Average', undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.15, '0.60', undefined, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel(currentBand.innerBand.movingAverage, undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.20, '1.00', 15, undefined, 'Center', thisObject.container, thisObject.fitFunction, undefined, undefined, 10);
|
||||
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel('Deviation', undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.85, '0.60', undefined, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel(currentBand.innerBand.deviation, X_AXIS, frameTitleHeight + frameBodyHeight * 0.80, '1.00', 15, undefined, 'Center', thisObject.container, thisObject.fitFunction, undefined, undefined, 10);
|
||||
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel('Standard Deviation', undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.95, '0.60', undefined, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel(currentBand.innerBand.standardDeviation, undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.90, '1.00', 15, undefined, 'Center', thisObject.container, thisObject.fitFunction, undefined, undefined, 10);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,921 +0,0 @@
|
||||
function newMastersPlottersBollingerBandsPercentageBandwidth() {
|
||||
|
||||
const MODULE_NAME = "Bands 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,
|
||||
draw: draw,
|
||||
recalculateScale: recalculateScale,
|
||||
|
||||
/* Events declared outside the plotter. */
|
||||
|
||||
onDailyFileLoaded: onDailyFileLoaded,
|
||||
|
||||
// Secondary functions and properties.
|
||||
|
||||
currentPercentageBandwidth: 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 plotAreaFrame = newCoordinateSystem(); // Used for full frame view.
|
||||
let plotAreaViewport = newCoordinateSystem(); // Used for viewport view.
|
||||
|
||||
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 percentageBandwidthArray = []; // Here we keep the percentageBandwidthArray to be ploted every time the Draw() function is called by the AAWebPlatform.
|
||||
|
||||
let zoomChangedEventSubscriptionId
|
||||
let offsetChangedEventSubscriptionId
|
||||
let dragFinishedEventSubscriptionId
|
||||
let dimmensionsChangedEventSubscriptionId
|
||||
let marketFilesUpdatedEventSubscriptionId
|
||||
let dailyFilesUpdatedEventSubscriptionId
|
||||
|
||||
return thisObject;
|
||||
|
||||
function finalize() {
|
||||
try {
|
||||
|
||||
/* Stop listening to the necesary events. */
|
||||
|
||||
UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.stopListening(zoomChangedEventSubscriptionId);
|
||||
UI.projects.superalgos.spaces.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;
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] finalize -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function initialize(pStorage, pDatetime, pTimeFrame, callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
/* Store the information received. */
|
||||
|
||||
marketFiles = pStorage.marketFiles[0];
|
||||
dailyFiles = pStorage.dailyFiles[0];
|
||||
|
||||
datetime = pDatetime;
|
||||
timeFrame = pTimeFrame;
|
||||
|
||||
/* 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.
|
||||
|
||||
recalculateScaleY();
|
||||
recalculateScaleX();
|
||||
|
||||
/* Now we set the right files according to current Period. */
|
||||
|
||||
marketFile = marketFiles.getFile(pTimeFrame);
|
||||
fileCursor = dailyFiles.getFileCursor(pTimeFrame);
|
||||
|
||||
/* Listen to the necesary events. */
|
||||
|
||||
zoomChangedEventSubscriptionId = UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.listenToEvent("Zoom Changed", onViewportZoomChanged);
|
||||
offsetChangedEventSubscriptionId = UI.projects.superalgos.spaces.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);
|
||||
|
||||
/* Get ready for plotting. */
|
||||
|
||||
recalculate();
|
||||
|
||||
dimmensionsChangedEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('Dimmensions Changed', function () {
|
||||
recalculateScaleY();
|
||||
recalculateScaleX();
|
||||
recalculate();
|
||||
})
|
||||
|
||||
callBackFunction();
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateScale() {
|
||||
|
||||
recalculateScaleY();
|
||||
recalculateScaleX();
|
||||
|
||||
}
|
||||
|
||||
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] 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) {
|
||||
|
||||
let newMarketFile = marketFiles.getFile(pTimeFrame);
|
||||
|
||||
if (newMarketFile !== undefined) {
|
||||
|
||||
marketFile = newMarketFile;
|
||||
recalculate();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
let newFileCursor = dailyFiles.getFileCursor(pTimeFrame);
|
||||
|
||||
if (newFileCursor !== undefined) {
|
||||
|
||||
fileCursor = newFileCursor;
|
||||
recalculate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] setTimeFrame -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function setDatetime(pDatetime) {
|
||||
|
||||
datetime = pDatetime;
|
||||
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
plotChart();
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] draw -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function recalculate() {
|
||||
|
||||
try {
|
||||
|
||||
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
|
||||
|
||||
recalculateUsingMarketFiles();
|
||||
|
||||
} else {
|
||||
|
||||
recalculateUsingDailyFiles();
|
||||
|
||||
}
|
||||
|
||||
thisObject.container.eventHandler.raiseEvent("Bands Changed", percentageBandwidthArray);
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] recalculate -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateUsingDailyFiles() {
|
||||
|
||||
try {
|
||||
|
||||
if (fileCursor === undefined) { return; } // We need to wait
|
||||
|
||||
if (fileCursor.files.size === 0) { return; } // We need to wait until there are files in the cursor
|
||||
|
||||
let daysOnSides = getSideDays(timeFrame);
|
||||
|
||||
let leftDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, plotAreaFrame);
|
||||
let rightDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight, thisObject.container, plotAreaFrame);
|
||||
|
||||
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());
|
||||
|
||||
percentageBandwidthArray = [];
|
||||
|
||||
while (currentDate.valueOf() <= farRightDate.valueOf() + ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
let stringDate = currentDate.getUTCFullYear() + '-' + pad(currentDate.getUTCMonth() + 1, 2) + '-' + pad(currentDate.getUTCDate(), 2);
|
||||
|
||||
let dailyFile = fileCursor.files.get(stringDate);
|
||||
|
||||
if (dailyFile !== undefined) {
|
||||
|
||||
for (let i = 0; i < dailyFile.length; i++) {
|
||||
|
||||
let percentageBandwidth = {
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
value: undefined,
|
||||
movingAverage: undefined,
|
||||
bandwidth: undefined
|
||||
};
|
||||
|
||||
percentageBandwidth.begin = dailyFile[i][0];
|
||||
percentageBandwidth.end = dailyFile[i][1];
|
||||
percentageBandwidth.value = dailyFile[i][2];
|
||||
percentageBandwidth.movingAverage = dailyFile[i][3];
|
||||
percentageBandwidth.bandwidth = dailyFile[i][4];
|
||||
|
||||
if (percentageBandwidth.begin >= farLeftDate.valueOf() && percentageBandwidth.end <= farRightDate.valueOf()) {
|
||||
|
||||
percentageBandwidthArray.push(percentageBandwidth);
|
||||
|
||||
if (datetime.valueOf() >= percentageBandwidth.begin && datetime.valueOf() <= percentageBandwidth.end) {
|
||||
|
||||
thisObject.currentPercentageBandwidth = percentageBandwidth;
|
||||
thisObject.container.eventHandler.raiseEvent("Current Percentage Bandwidth Changed", thisObject.currentPercentageBandwidth);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS);
|
||||
}
|
||||
|
||||
/* Lests check if all the visible screen is going to be covered by percentageBandwidthArray. */
|
||||
|
||||
let lowerEnd = leftDate.valueOf();
|
||||
let upperEnd = rightDate.valueOf();
|
||||
|
||||
if (percentageBandwidthArray.length > 0) {
|
||||
|
||||
if (percentageBandwidthArray[0].begin > lowerEnd || percentageBandwidthArray[percentageBandwidthArray.length - 1].end < upperEnd) {
|
||||
|
||||
setTimeout(recalculate, 2000);
|
||||
|
||||
//console.log("File missing while calculating percentageBandwidthArray, scheduling a recalculation in 2 seconds.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//console.log("Olivia > recalculateUsingDailyFiles > total percentageBandwidthArray generated : " + percentageBandwidthArray.length);
|
||||
|
||||
} 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 = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, plotAreaFrame);
|
||||
let rightDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight, thisObject.container, plotAreaFrame);
|
||||
|
||||
let dateDiff = rightDate.valueOf() - leftDate.valueOf();
|
||||
|
||||
leftDate = new Date(leftDate.valueOf() - dateDiff * 1.5);
|
||||
rightDate = new Date(rightDate.valueOf() + dateDiff * 1.5);
|
||||
|
||||
percentageBandwidthArray = [];
|
||||
|
||||
for (let i = 0; i < marketFile.length; i++) {
|
||||
|
||||
let percentageBandwidth = {
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
value: undefined,
|
||||
movingAverage: undefined,
|
||||
bandwidth: undefined
|
||||
};
|
||||
|
||||
percentageBandwidth.begin = marketFile[i][0];
|
||||
percentageBandwidth.end = marketFile[i][1];
|
||||
percentageBandwidth.value = marketFile[i][2];
|
||||
percentageBandwidth.movingAverage = marketFile[i][3];
|
||||
percentageBandwidth.bandwidth = marketFile[i][4];
|
||||
|
||||
if (percentageBandwidth.begin >= leftDate.valueOf() && percentageBandwidth.end <= rightDate.valueOf()) {
|
||||
|
||||
percentageBandwidthArray.push(percentageBandwidth);
|
||||
|
||||
if (datetime.valueOf() >= percentageBandwidth.begin && datetime.valueOf() <= percentageBandwidth.end) {
|
||||
|
||||
thisObject.currentPercentageBandwidth = percentageBandwidth;
|
||||
thisObject.container.eventHandler.raiseEvent("Current Percentage Bandwidth Changed", thisObject.currentPercentageBandwidth);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//console.log("Olivia > recalculateUsingMarketFiles > total percentageBandwidthArray generated : " + percentageBandwidthArray.length);
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingMarketFiles -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateScaleX() {
|
||||
|
||||
try {
|
||||
|
||||
var minValue = {
|
||||
x: MIN_PLOTABLE_DATE.valueOf()
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf()
|
||||
};
|
||||
|
||||
plotAreaViewport.initializeX(
|
||||
minValue,
|
||||
maxValue,
|
||||
thisObject.container.frame.width
|
||||
);
|
||||
|
||||
plotAreaFrame.initializeX(
|
||||
minValue,
|
||||
maxValue,
|
||||
thisObject.container.frame.width
|
||||
);
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateScaleX -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateScaleY() {
|
||||
|
||||
try {
|
||||
|
||||
var minValue = {
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
y: 0
|
||||
};
|
||||
|
||||
maxValue.y = 100;
|
||||
|
||||
plotAreaViewport.initializeY(
|
||||
minValue,
|
||||
maxValue,
|
||||
UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.y
|
||||
);
|
||||
|
||||
plotAreaFrame.initializeY(
|
||||
minValue,
|
||||
maxValue,
|
||||
thisObject.container.frame.height
|
||||
);
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateScaleY -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function plotChart() {
|
||||
|
||||
try {
|
||||
|
||||
let userPosition = getUserPosition()
|
||||
let userPositionDate = userPosition.point.x
|
||||
|
||||
let percentageBandwidth;
|
||||
let previousBand;
|
||||
|
||||
if (percentageBandwidthArray.length > 0) {
|
||||
|
||||
/* This next section is to get ready in order to be able to plot dinamically constrained to the viewport */
|
||||
|
||||
let visibleHeight = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.y;
|
||||
|
||||
let frameCorner1 = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
|
||||
let frameCorner2 = {
|
||||
x: thisObject.container.frame.width,
|
||||
y: thisObject.container.frame.height
|
||||
};
|
||||
|
||||
/* Now the transformations. */
|
||||
|
||||
frameCorner1 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(frameCorner1, thisObject.container.frame.container);
|
||||
frameCorner2 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(frameCorner2, thisObject.container.frame.container);
|
||||
|
||||
let frameHeightInViewPort = frameCorner2.y - frameCorner1.y;
|
||||
let pbChartHeight = 20;
|
||||
let pbOffset = 100 / 5 * 4;
|
||||
|
||||
/* Now we calculate and plot the percentageBandwidthArray */
|
||||
|
||||
for (let i = 1; i < percentageBandwidthArray.length; i++) {
|
||||
|
||||
percentageBandwidth = percentageBandwidthArray[i];
|
||||
previousBand = percentageBandwidthArray[i - 1];
|
||||
|
||||
/* Here we will draw the percent bandwidth chart */
|
||||
|
||||
let currentPercentBandwidth = percentageBandwidth.value * pbChartHeight / 100;
|
||||
if (currentPercentBandwidth > pbChartHeight) { currentPercentBandwidth = pbChartHeight };
|
||||
if (currentPercentBandwidth < 0) { currentPercentBandwidth = 0 };
|
||||
|
||||
let previousPercentBandwidth = previousBand.value * pbChartHeight / 100;
|
||||
if (previousPercentBandwidth > pbChartHeight) { previousPercentBandwidth = pbChartHeight };
|
||||
if (previousPercentBandwidth < 0) { previousPercentBandwidth = 0 };
|
||||
|
||||
let currentMovingAverage = percentageBandwidth.movingAverage * pbChartHeight / 100;
|
||||
let previousMovingAverage = previousBand.movingAverage * pbChartHeight / 100;
|
||||
|
||||
let currentBandwidth = percentageBandwidth.bandwidth * 100 * pbChartHeight / 100;
|
||||
let previousBandwidth = previousBand.bandwidth * 100 * pbChartHeight / 100;
|
||||
|
||||
let pbPoint1;
|
||||
let pbPoint2;
|
||||
let pbPoint3;
|
||||
let pbPoint4;
|
||||
let pbPoint5;
|
||||
let pbPoint6;
|
||||
let pbPoint7;
|
||||
let pbPoint8;
|
||||
let pbPoint9;
|
||||
let pbPoint10;
|
||||
|
||||
function calculateCoordinates(plot, height) {
|
||||
|
||||
pbPoint1 = {
|
||||
x: percentageBandwidth.begin,
|
||||
y: previousPercentBandwidth + pbOffset
|
||||
};
|
||||
|
||||
pbPoint2 = {
|
||||
x: percentageBandwidth.end,
|
||||
y: currentPercentBandwidth + pbOffset
|
||||
};
|
||||
|
||||
/* Points needed for the lines */
|
||||
|
||||
pbPoint3 = {
|
||||
x: 0,
|
||||
y: 0 * pbChartHeight / 100 + pbOffset
|
||||
};
|
||||
|
||||
pbPoint4 = {
|
||||
x: 0,
|
||||
y: 30 * pbChartHeight / 100 + pbOffset
|
||||
};
|
||||
|
||||
pbPoint5 = {
|
||||
x: 0,
|
||||
y: 70 * pbChartHeight / 100 + pbOffset
|
||||
};
|
||||
|
||||
pbPoint6 = {
|
||||
x: 0,
|
||||
y: 100 * pbChartHeight / 100 + pbOffset
|
||||
};
|
||||
|
||||
/* Moving Average */
|
||||
|
||||
pbPoint7 = {
|
||||
x: percentageBandwidth.begin,
|
||||
y: previousMovingAverage + pbOffset
|
||||
};
|
||||
|
||||
pbPoint8 = {
|
||||
x: percentageBandwidth.end,
|
||||
y: currentMovingAverage + pbOffset
|
||||
};
|
||||
|
||||
/* Bandwidth */
|
||||
|
||||
pbPoint9 = {
|
||||
x: percentageBandwidth.begin,
|
||||
y: previousBandwidth + pbOffset
|
||||
};
|
||||
|
||||
pbPoint10 = {
|
||||
x: percentageBandwidth.end,
|
||||
y: currentBandwidth + pbOffset
|
||||
};
|
||||
|
||||
pbPoint1 = plot.transformThisPoint(pbPoint1);
|
||||
pbPoint2 = plot.transformThisPoint(pbPoint2);
|
||||
|
||||
pbPoint3 = plot.transformThisPoint(pbPoint3);
|
||||
pbPoint4 = plot.transformThisPoint(pbPoint4);
|
||||
pbPoint5 = plot.transformThisPoint(pbPoint5);
|
||||
pbPoint6 = plot.transformThisPoint(pbPoint6);
|
||||
|
||||
pbPoint7 = plot.transformThisPoint(pbPoint7);
|
||||
pbPoint8 = plot.transformThisPoint(pbPoint8);
|
||||
|
||||
pbPoint9 = plot.transformThisPoint(pbPoint9);
|
||||
pbPoint10 = plot.transformThisPoint(pbPoint10);
|
||||
|
||||
pbPoint1 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pbPoint1, thisObject.container);
|
||||
pbPoint2 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pbPoint2, thisObject.container);
|
||||
|
||||
pbPoint3 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pbPoint3, thisObject.container);
|
||||
pbPoint4 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pbPoint4, thisObject.container);
|
||||
pbPoint5 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pbPoint5, thisObject.container);
|
||||
pbPoint6 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pbPoint6, thisObject.container);
|
||||
|
||||
pbPoint7 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pbPoint7, thisObject.container);
|
||||
pbPoint8 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pbPoint8, thisObject.container);
|
||||
|
||||
pbPoint9 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pbPoint9, thisObject.container);
|
||||
pbPoint10 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pbPoint10, thisObject.container);
|
||||
|
||||
if (pbPoint1.x < UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.x || pbPoint2.x > UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
if (calculateCoordinates(plotAreaFrame, thisObject.container.frame.height) === false) { continue; } // We try to see if it fits in the visible area.
|
||||
|
||||
if (frameHeightInViewPort > visibleHeight * 2 / 3) {
|
||||
|
||||
if (calculateCoordinates(plotAreaViewport, visibleHeight) === false) {
|
||||
continue;
|
||||
} // We snap t to the view port.
|
||||
|
||||
/* Now we set the real value of y. */
|
||||
|
||||
pbPoint1.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - (previousPercentBandwidth + pbOffset) * plotAreaViewport.scale.y;
|
||||
pbPoint2.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - (currentPercentBandwidth + pbOffset) * plotAreaViewport.scale.y;
|
||||
|
||||
pbPoint3.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - (0 * pbChartHeight / 100 + pbOffset) * plotAreaViewport.scale.y;
|
||||
pbPoint4.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - (30 * pbChartHeight / 100 + pbOffset) * plotAreaViewport.scale.y;
|
||||
pbPoint5.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - (70 * pbChartHeight / 100 + pbOffset) * plotAreaViewport.scale.y;
|
||||
pbPoint6.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - (100 * pbChartHeight / 100 + pbOffset) * plotAreaViewport.scale.y;
|
||||
|
||||
pbPoint7.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - (previousMovingAverage + pbOffset) * plotAreaViewport.scale.y;
|
||||
pbPoint8.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - (currentMovingAverage + pbOffset) * plotAreaViewport.scale.y;
|
||||
|
||||
pbPoint9.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - (previousBandwidth + pbOffset) * plotAreaViewport.scale.y;
|
||||
pbPoint10.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - (currentBandwidth + pbOffset) * plotAreaViewport.scale.y;
|
||||
|
||||
}
|
||||
|
||||
/* Everything must fit within the visible area */
|
||||
|
||||
pbPoint1 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(pbPoint1);
|
||||
pbPoint2 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(pbPoint2);
|
||||
|
||||
pbPoint3 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(pbPoint3);
|
||||
pbPoint4 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(pbPoint4);
|
||||
pbPoint5 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(pbPoint5);
|
||||
pbPoint6 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(pbPoint6);
|
||||
|
||||
pbPoint7 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(pbPoint7);
|
||||
pbPoint8 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(pbPoint8);
|
||||
|
||||
pbPoint9 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(pbPoint9);
|
||||
pbPoint10 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(pbPoint10);
|
||||
|
||||
|
||||
/* Now the drawing of the lines */
|
||||
|
||||
let bgOpacityA = 0.05;
|
||||
let bgOpacityB = 0.05;
|
||||
let bgOpacityC = 0.05;
|
||||
|
||||
let fgOpacity = '1';
|
||||
|
||||
let lineWidthA = 0.2;
|
||||
let lineWidthB = 0.2;
|
||||
let lineWidthC = 0.2;
|
||||
|
||||
if (pbPoint1.y > pbPoint4.y || pbPoint2.y > pbPoint4.y) {
|
||||
bgOpacityA = bgOpacityA * 2;
|
||||
}
|
||||
|
||||
if (pbPoint1.y < pbPoint5.y || pbPoint2.y < pbPoint5.y) {
|
||||
bgOpacityC = bgOpacityC * 2;
|
||||
}
|
||||
|
||||
if (pbPoint1.y >= pbPoint3.y || pbPoint2.y >= pbPoint3.y) {
|
||||
bgOpacityA = bgOpacityA * 1.5;
|
||||
lineWidthA = lineWidthA * 2;
|
||||
}
|
||||
|
||||
if (pbPoint1.y <= pbPoint6.y || pbPoint2.y <= pbPoint6.y) {
|
||||
bgOpacityC = bgOpacityC * 1.5;
|
||||
lineWidthC = lineWidthC * 2;
|
||||
}
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(pbPoint1.x, pbPoint3.y);
|
||||
browserCanvasContext.lineTo(pbPoint2.x, pbPoint3.y);
|
||||
browserCanvasContext.lineTo(pbPoint2.x, pbPoint4.y);
|
||||
browserCanvasContext.lineTo(pbPoint1.x, pbPoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GOLDEN_ORANGE + ',' + bgOpacityA + ' )';
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(pbPoint1.x, pbPoint4.y);
|
||||
browserCanvasContext.lineTo(pbPoint2.x, pbPoint4.y);
|
||||
browserCanvasContext.lineTo(pbPoint2.x, pbPoint5.y);
|
||||
browserCanvasContext.lineTo(pbPoint1.x, pbPoint5.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + bgOpacityB + ')';
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(pbPoint1.x, pbPoint5.y);
|
||||
browserCanvasContext.lineTo(pbPoint2.x, pbPoint5.y);
|
||||
browserCanvasContext.lineTo(pbPoint2.x, pbPoint6.y);
|
||||
browserCanvasContext.lineTo(pbPoint1.x, pbPoint6.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GOLDEN_ORANGE + ', ' + bgOpacityC + ')';
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(pbPoint1.x, pbPoint3.y);
|
||||
browserCanvasContext.lineTo(pbPoint2.x, pbPoint3.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GOLDEN_ORANGE + ', ' + fgOpacity + ')';
|
||||
browserCanvasContext.lineWidth = lineWidthA;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(pbPoint1.x, pbPoint4.y);
|
||||
browserCanvasContext.lineTo(pbPoint2.x, pbPoint4.y);
|
||||
browserCanvasContext.moveTo(pbPoint1.x, pbPoint5.y);
|
||||
browserCanvasContext.lineTo(pbPoint2.x, pbPoint5.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GOLDEN_ORANGE + ', ' + fgOpacity + ')';
|
||||
browserCanvasContext.lineWidth = lineWidthB;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(pbPoint1.x, pbPoint6.y);
|
||||
browserCanvasContext.lineTo(pbPoint2.x, pbPoint6.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GOLDEN_ORANGE + ', ' + fgOpacity + ')';
|
||||
browserCanvasContext.lineWidth = lineWidthC;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
/* Now the drawing of the percentage bandwidth*/
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(pbPoint1.x, pbPoint1.y);
|
||||
browserCanvasContext.lineTo(pbPoint2.x, pbPoint2.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GOLDEN_ORANGE + ', 1)';
|
||||
|
||||
if (userPositionDate >= percentageBandwidth.begin && userPositionDate <= percentageBandwidth.end) {
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.BLACK + ', 1)';
|
||||
}
|
||||
|
||||
browserCanvasContext.lineWidth = 0.2;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
/* Now the drawing of the moving average*/
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(pbPoint7.x, pbPoint7.y);
|
||||
browserCanvasContext.lineTo(pbPoint8.x, pbPoint8.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (pbPoint7.y > pbPoint8.y) {
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', 1)';
|
||||
} else {
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', 1)';
|
||||
}
|
||||
|
||||
if (userPositionDate >= percentageBandwidth.begin && userPositionDate <= percentageBandwidth.end) {
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.BLACK + ', 1)';
|
||||
}
|
||||
|
||||
browserCanvasContext.lineWidth = 0.2;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
/* Now the drawing of the bandwidth*/
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(pbPoint9.x, pbPoint9.y);
|
||||
browserCanvasContext.lineTo(pbPoint10.x, pbPoint10.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREEN + ', 1)';
|
||||
|
||||
if (userPositionDate >= percentageBandwidth.begin && userPositionDate <= percentageBandwidth.end) {
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.BLACK + ', 1)';
|
||||
}
|
||||
|
||||
browserCanvasContext.setLineDash([1, 4])
|
||||
browserCanvasContext.lineWidth = 1
|
||||
browserCanvasContext.stroke()
|
||||
browserCanvasContext.setLineDash([0, 0])
|
||||
}
|
||||
}
|
||||
|
||||
} 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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"displayName": "Plotters Bollinger Bands",
|
||||
"codeName": "PlottersBollingerBands",
|
||||
"dataMine": "Masters",
|
||||
"modules": [
|
||||
{
|
||||
"codeName": "BollingerBands",
|
||||
"moduleName": "BollingerBands",
|
||||
"description": "Plots Bollinger Bands.",
|
||||
"profilePicture": "BollingerBands.png",
|
||||
"panels": [
|
||||
{
|
||||
"codeName": "BollingerBandsPanel",
|
||||
"moduleName": "BollingerBandsPanel",
|
||||
"event": "Current Record Changed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"codeName": "PercentageBandwidth",
|
||||
"moduleName": "PercentageBandwidth",
|
||||
"description": "Plots Bollinger Bands.",
|
||||
"profilePicture": "PercentageBandwidth.png",
|
||||
"panels": [
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
|
||||
function newMastersPlottersCandlesVolumesCandlesCandlePanel() {
|
||||
|
||||
let thisObject = {
|
||||
fitFunction: undefined,
|
||||
container: undefined,
|
||||
isVisible: true,
|
||||
onRecordChange: onRecordChange,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
};
|
||||
|
||||
thisObject.container = newContainer();
|
||||
thisObject.container.initialize();
|
||||
thisObject.container.frame.containerName = "Candle";
|
||||
|
||||
let currentCandle;
|
||||
let upDownButton
|
||||
|
||||
return thisObject;
|
||||
|
||||
function finalize() {
|
||||
thisObject.container.finalize()
|
||||
thisObject.container = undefined
|
||||
thisObject.fitFunction = undefined
|
||||
thisObject.isVisible = undefined
|
||||
|
||||
currentCandle = undefined
|
||||
upDownButton.finalize()
|
||||
upDownButton = undefined
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL;
|
||||
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL;
|
||||
|
||||
thisObject.container.frame.position.x = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight.x - thisObject.container.frame.width * 2;
|
||||
thisObject.container.frame.position.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.y - thisObject.container.frame.height;
|
||||
|
||||
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) {
|
||||
|
||||
currentCandle = lastCurrentCandle;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function draw() {
|
||||
if (thisObject.isVisible !== true) { return }
|
||||
thisObject.container.frame.draw(false, false, true, thisObject.fitFunction);
|
||||
|
||||
plotCurrentCandleInfo();
|
||||
|
||||
upDownButton.draw()
|
||||
|
||||
}
|
||||
|
||||
|
||||
function plotCurrentCandleInfo() {
|
||||
|
||||
if (currentCandle === undefined) { return; }
|
||||
if (currentCandle.innerCandle === 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;
|
||||
|
||||
let candlePoint1 = {
|
||||
x: X_AXIS - currentCandle.bodyWidth / 2,
|
||||
y: Y_AXIS - currentCandle.bodyHeight / 2
|
||||
};
|
||||
|
||||
let candlePoint2 = {
|
||||
x: X_AXIS + currentCandle.bodyWidth / 2,
|
||||
y: Y_AXIS - currentCandle.bodyHeight / 2
|
||||
};
|
||||
|
||||
let candlePoint3 = {
|
||||
x: X_AXIS + currentCandle.bodyWidth / 2,
|
||||
y: Y_AXIS + currentCandle.bodyHeight / 2
|
||||
};
|
||||
|
||||
let candlePoint4 = {
|
||||
x: X_AXIS - currentCandle.bodyWidth / 2,
|
||||
y: Y_AXIS + currentCandle.bodyHeight / 2
|
||||
};
|
||||
|
||||
|
||||
let stickPoint1 = {
|
||||
x: X_AXIS - currentCandle.stickWidth / 2,
|
||||
y: candlePoint1.y - currentCandle.stickStart
|
||||
};
|
||||
|
||||
let stickPoint2 = {
|
||||
x: X_AXIS + currentCandle.stickWidth / 2,
|
||||
y: candlePoint1.y - currentCandle.stickStart
|
||||
};
|
||||
|
||||
let stickPoint3 = {
|
||||
x: X_AXIS + currentCandle.stickWidth / 2,
|
||||
y: candlePoint1.y - currentCandle.stickStart + currentCandle.stickHeight
|
||||
};
|
||||
|
||||
let stickPoint4 = {
|
||||
x: X_AXIS - currentCandle.stickWidth / 2,
|
||||
y: candlePoint1.y - currentCandle.stickStart + currentCandle.stickHeight
|
||||
};
|
||||
|
||||
|
||||
/* Extra bounderies due to constrained space */
|
||||
|
||||
const upperLimit = frameTitleHeight + frameBodyHeight * 0.15;
|
||||
const downLimit = frameTitleHeight + frameBodyHeight * 0.85;
|
||||
|
||||
if (candlePoint1.y < upperLimit) {
|
||||
|
||||
candlePoint1.y = upperLimit;
|
||||
candlePoint2.y = upperLimit;
|
||||
|
||||
}
|
||||
|
||||
if (stickPoint1.y < upperLimit) {
|
||||
|
||||
stickPoint1.y = upperLimit;
|
||||
stickPoint2.y = upperLimit;
|
||||
|
||||
}
|
||||
|
||||
if (candlePoint3.y < upperLimit) {
|
||||
|
||||
candlePoint3.y = upperLimit;
|
||||
candlePoint4.y = upperLimit;
|
||||
|
||||
}
|
||||
|
||||
if (stickPoint3.y < upperLimit) {
|
||||
|
||||
stickPoint3.y = upperLimit;
|
||||
stickPoint4.y = upperLimit;
|
||||
|
||||
}
|
||||
|
||||
if (candlePoint1.y > downLimit) {
|
||||
|
||||
candlePoint1.y = downLimit;
|
||||
candlePoint2.y = downLimit;
|
||||
|
||||
}
|
||||
|
||||
if (stickPoint1.y > downLimit) {
|
||||
|
||||
stickPoint1.y = downLimit;
|
||||
stickPoint2.y = downLimit;
|
||||
|
||||
}
|
||||
|
||||
if (candlePoint3.y > downLimit) {
|
||||
|
||||
candlePoint3.y = downLimit;
|
||||
candlePoint4.y = downLimit;
|
||||
|
||||
}
|
||||
|
||||
if (stickPoint3.y > downLimit) {
|
||||
|
||||
stickPoint3.y = downLimit;
|
||||
stickPoint4.y = downLimit;
|
||||
|
||||
}
|
||||
|
||||
const leftLimit = thisObject.container.frame.width * 0.42;
|
||||
const rightLimit = thisObject.container.frame.width * 0.58;
|
||||
|
||||
if (candlePoint1.x < leftLimit) {
|
||||
|
||||
candlePoint1.x = leftLimit;
|
||||
candlePoint4.x = leftLimit;
|
||||
|
||||
}
|
||||
|
||||
if (stickPoint1.x < leftLimit) {
|
||||
|
||||
stickPoint1.x = leftLimit;
|
||||
stickPoint4.x = leftLimit;
|
||||
|
||||
}
|
||||
|
||||
if (candlePoint4.x < leftLimit) {
|
||||
|
||||
candlePoint4.x = leftLimit;
|
||||
candlePoint1.x = leftLimit;
|
||||
|
||||
}
|
||||
|
||||
if (stickPoint4.x < leftLimit) {
|
||||
|
||||
stickPoint4.x = leftLimit;
|
||||
stickPoint1.x = leftLimit;
|
||||
|
||||
}
|
||||
|
||||
if (candlePoint2.x > rightLimit) {
|
||||
|
||||
candlePoint2.x = rightLimit;
|
||||
candlePoint3.x = rightLimit;
|
||||
|
||||
}
|
||||
|
||||
if (stickPoint2.x > rightLimit) {
|
||||
|
||||
stickPoint2.x = rightLimit;
|
||||
stickPoint3.x = rightLimit;
|
||||
|
||||
}
|
||||
|
||||
if (candlePoint3.x > rightLimit) {
|
||||
|
||||
candlePoint3.x = rightLimit;
|
||||
candlePoint2.x = rightLimit;
|
||||
|
||||
}
|
||||
|
||||
if (stickPoint3.x > rightLimit) {
|
||||
|
||||
stickPoint3.x = rightLimit;
|
||||
stickPoint2.x = rightLimit;
|
||||
|
||||
}
|
||||
|
||||
|
||||
candlePoint1 = thisObject.container.frame.frameThisPoint(candlePoint1);
|
||||
candlePoint2 = thisObject.container.frame.frameThisPoint(candlePoint2);
|
||||
candlePoint3 = thisObject.container.frame.frameThisPoint(candlePoint3);
|
||||
candlePoint4 = thisObject.container.frame.frameThisPoint(candlePoint4);
|
||||
|
||||
candlePoint1 = thisObject.fitFunction(candlePoint1)
|
||||
candlePoint2 = thisObject.fitFunction(candlePoint2)
|
||||
candlePoint3 = thisObject.fitFunction(candlePoint3)
|
||||
candlePoint4 = thisObject.fitFunction(candlePoint4)
|
||||
|
||||
stickPoint1 = thisObject.container.frame.frameThisPoint(stickPoint1);
|
||||
stickPoint2 = thisObject.container.frame.frameThisPoint(stickPoint2);
|
||||
stickPoint3 = thisObject.container.frame.frameThisPoint(stickPoint3);
|
||||
stickPoint4 = thisObject.container.frame.frameThisPoint(stickPoint4);
|
||||
|
||||
stickPoint1 = thisObject.fitFunction(stickPoint1)
|
||||
stickPoint2 = thisObject.fitFunction(stickPoint2)
|
||||
stickPoint3 = thisObject.fitFunction(stickPoint3)
|
||||
stickPoint4 = thisObject.fitFunction(stickPoint4)
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(stickPoint1.x, stickPoint1.y);
|
||||
browserCanvasContext.lineTo(stickPoint2.x, stickPoint2.y);
|
||||
browserCanvasContext.lineTo(stickPoint3.x, stickPoint3.y);
|
||||
browserCanvasContext.lineTo(stickPoint4.x, stickPoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', 1)';
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(candlePoint1.x, candlePoint1.y);
|
||||
browserCanvasContext.lineTo(candlePoint2.x, candlePoint2.y);
|
||||
browserCanvasContext.lineTo(candlePoint3.x, candlePoint3.y);
|
||||
browserCanvasContext.lineTo(candlePoint4.x, candlePoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
const OPACITY = '1';
|
||||
|
||||
if (currentCandle.innerCandle.direction === 'up') { browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + OPACITY + ')'; }
|
||||
if (currentCandle.innerCandle.direction === 'down') { browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + OPACITY + ')'; }
|
||||
if (currentCandle.innerCandle.direction === 'side') { browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.DARK + ', ' + OPACITY + ')'; }
|
||||
|
||||
if (currentCandle.innerCandle.direction === 'up') { browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + OPACITY + ')'; }
|
||||
if (currentCandle.innerCandle.direction === 'down') { browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + OPACITY + ')'; }
|
||||
if (currentCandle.innerCandle.direction === 'side') { browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', ' + OPACITY + ')'; }
|
||||
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
/* put the labels with the candles values */
|
||||
|
||||
let y;
|
||||
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel('Max', undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.05, '0.60', undefined, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel(currentCandle.innerCandle.max, undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.10, '1.00', 15, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel('Min', undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.95, '0.60', undefined, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel(currentCandle.innerCandle.min, undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.90, '1.00', 15, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
|
||||
y = Y_AXIS - currentCandle.bodyHeight / 2;
|
||||
|
||||
if (y < frameTitleHeight + frameBodyHeight * 0.15) { y = frameTitleHeight + frameBodyHeight * 0.15; }
|
||||
if (y > frameTitleHeight + frameBodyHeight * 0.80) { y = frameTitleHeight + frameBodyHeight * 0.80; }
|
||||
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel('Open', undefined, undefined, X_AXIS * 2 / 5, y, '0.60', undefined, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel(currentCandle.innerCandle.open, undefined, undefined, X_AXIS * 2 / 5, y + frameBodyHeight * 0.05, '1.00', 15, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
|
||||
y = Y_AXIS + currentCandle.bodyHeight / 2;
|
||||
|
||||
if (y < frameTitleHeight + frameBodyHeight * 0.15) { y = frameTitleHeight + frameBodyHeight * 0.15; }
|
||||
if (y > frameTitleHeight + frameBodyHeight * 0.80) { y = frameTitleHeight + frameBodyHeight * 0.80; }
|
||||
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel('Close', undefined, undefined, X_AXIS * 7 / 5, y, '0.60', undefined, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel(currentCandle.innerCandle.close, undefined, undefined, X_AXIS * 7 / 5, y + frameBodyHeight * 0.05, '1.00', 15, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,810 +0,0 @@
|
||||
function newMastersPlottersCandlesVolumesCandles() {
|
||||
|
||||
const MODULE_NAME = "Candles Plotter";
|
||||
const ERROR_LOG = true;
|
||||
const INTENSIVE_LOG = false;
|
||||
const logger = newWebDebugLog();
|
||||
logger.fileName = MODULE_NAME;
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
container: undefined,
|
||||
fitFunction: undefined,
|
||||
getContainer: getContainer,
|
||||
setTimeFrame: setTimeFrame,
|
||||
setDatetime: setDatetime,
|
||||
setCoordinateSystem: setCoordinateSystem,
|
||||
draw: draw,
|
||||
onDailyFileLoaded: onDailyFileLoaded,
|
||||
currentCandle: undefined
|
||||
};
|
||||
|
||||
/* this is part of the module template */
|
||||
|
||||
thisObject.container = newContainer()
|
||||
thisObject.container.initialize(MODULE_NAME)
|
||||
|
||||
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 candles = []; // Here we keep the candles to be ploted every time the Draw() function is called by the AAWebPlatform.
|
||||
|
||||
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)
|
||||
UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.stopListening(zoomChangedEventSubscriptionId);
|
||||
UI.projects.superalgos.spaces.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 {
|
||||
|
||||
/* 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 = UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.listenToEvent("Zoom Changed", onViewportZoomChanged);
|
||||
offsetChangedEventSubscriptionId = UI.projects.superalgos.spaces.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();
|
||||
|
||||
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 = UI.projects.superalgos.utilities.dateRateTransformations.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 (thisObject.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return thisObject.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) {
|
||||
let newMarketFile = marketFiles.getFile(pTimeFrame);
|
||||
if (newMarketFile !== undefined) {
|
||||
marketFile = newMarketFile;
|
||||
recalculate();
|
||||
}
|
||||
|
||||
} else {
|
||||
let newFileCursor = dailyFiles.getFileCursor(pTimeFrame);
|
||||
if (newFileCursor !== undefined) {
|
||||
fileCursor = newFileCursor;
|
||||
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."); }
|
||||
|
||||
thisObject.container.frame.draw();
|
||||
|
||||
return plotChart();
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] draw -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function recalculate() {
|
||||
|
||||
try {
|
||||
|
||||
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
|
||||
|
||||
recalculateUsingMarketFiles();
|
||||
|
||||
} else {
|
||||
|
||||
recalculateUsingDailyFiles();
|
||||
|
||||
}
|
||||
|
||||
thisObject.container.eventHandler.raiseEvent("Candles Changed", candles);
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] recalculate -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateUsingDailyFiles() {
|
||||
|
||||
try {
|
||||
|
||||
if (fileCursor === undefined) { return; } // We need to wait
|
||||
|
||||
if (fileCursor.files.size === 0) { return; } // We need to wait until there are files in the cursor
|
||||
|
||||
let daysOnSides = getSideDays(timeFrame);
|
||||
|
||||
let leftDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
|
||||
let rightDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.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());
|
||||
|
||||
candles = [];
|
||||
|
||||
while (currentDate.valueOf() <= farRightDate.valueOf() + ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
let stringDate = currentDate.getUTCFullYear() + '-' + pad(currentDate.getUTCMonth() + 1, 2) + '-' + pad(currentDate.getUTCDate(), 2);
|
||||
|
||||
let dailyFile = fileCursor.files.get(stringDate);
|
||||
|
||||
if (dailyFile !== undefined) {
|
||||
|
||||
for (let i = 0; i < dailyFile.length; i++) {
|
||||
|
||||
let candle = {
|
||||
open: undefined,
|
||||
close: undefined,
|
||||
min: 10000000000000,
|
||||
max: 0,
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
direction: undefined
|
||||
};
|
||||
|
||||
candle.min = dailyFile[i][0];
|
||||
candle.max = dailyFile[i][1];
|
||||
|
||||
candle.open = dailyFile[i][2];
|
||||
candle.close = dailyFile[i][3];
|
||||
|
||||
candle.begin = dailyFile[i][4];
|
||||
candle.end = dailyFile[i][5];
|
||||
|
||||
if (candle.open > candle.close) { candle.direction = 'down'; }
|
||||
if (candle.open < candle.close) { candle.direction = 'up'; }
|
||||
if (candle.open === candle.close) { candle.direction = 'side'; }
|
||||
|
||||
/* Contributing to Auto-Scale*/
|
||||
if (i === 0) {
|
||||
coordinateSystem.reportXValue(candle.begin)
|
||||
}
|
||||
if (i === dailyFile.length - 1) {
|
||||
coordinateSystem.reportXValue(candle.end)
|
||||
}
|
||||
|
||||
if (
|
||||
(candle.begin >= farLeftDate.valueOf() && candle.end <= farRightDate.valueOf()) &&
|
||||
(candle.begin >= coordinateSystem.min.x && candle.end <= coordinateSystem.max.x)
|
||||
) {
|
||||
|
||||
candles.push(candle);
|
||||
|
||||
if (datetime.valueOf() >= candle.begin && datetime.valueOf() <= candle.end) {
|
||||
|
||||
thisObject.currentCandle = candle;
|
||||
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.currentCandle);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS);
|
||||
}
|
||||
|
||||
/* Lests check if all the visible screen is going to be covered by candles. */
|
||||
|
||||
let lowerEnd = leftDate.valueOf();
|
||||
let upperEnd = rightDate.valueOf();
|
||||
|
||||
if (candles.length > 0) {
|
||||
if (candles[0].begin > lowerEnd || candles[candles.length - 1].end < upperEnd) {
|
||||
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 = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
|
||||
let rightDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.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);
|
||||
|
||||
candles = [];
|
||||
|
||||
for (let i = 0; i < marketFile.length; i++) {
|
||||
|
||||
let candle = {
|
||||
open: undefined,
|
||||
close: undefined,
|
||||
min: 10000000000000,
|
||||
max: 0,
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
direction: undefined
|
||||
};
|
||||
|
||||
candle.min = marketFile[i][0];
|
||||
candle.max = marketFile[i][1];
|
||||
|
||||
candle.open = marketFile[i][2];
|
||||
candle.close = marketFile[i][3];
|
||||
|
||||
candle.begin = marketFile[i][4];
|
||||
candle.end = marketFile[i][5];
|
||||
|
||||
if (candle.open > candle.close) { candle.direction = 'down'; }
|
||||
if (candle.open < candle.close) { candle.direction = 'up'; }
|
||||
if (candle.open === candle.close) { candle.direction = 'side'; }
|
||||
|
||||
/* Contributing to Auto-Scale*/
|
||||
if (i === 0) {
|
||||
coordinateSystem.reportXValue(candle.begin)
|
||||
}
|
||||
if (i === marketFile.length - 1) {
|
||||
coordinateSystem.reportXValue(candle.end)
|
||||
}
|
||||
|
||||
if (
|
||||
(candle.begin >= leftDate.valueOf() && candle.end <= rightDate.valueOf()) &&
|
||||
(candle.begin >= coordinateSystem.min.x && candle.end <= coordinateSystem.max.x)
|
||||
) {
|
||||
|
||||
candles.push(candle);
|
||||
|
||||
if (datetime.valueOf() >= candle.begin && datetime.valueOf() <= candle.end) {
|
||||
|
||||
thisObject.currentCandle = candle;
|
||||
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.currentCandle);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingMarketFiles -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function plotChart() {
|
||||
|
||||
try {
|
||||
let elementsPlotted = 0
|
||||
let lowResolution = false
|
||||
if (UI.projects.superalgos.spaces.chartingSpace.viewport.zoomTargetLevel < UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_PLOTTING_IN_LOW_RESOLUTION) {
|
||||
if (candles.length > 100) {
|
||||
lowResolution = true
|
||||
}
|
||||
}
|
||||
|
||||
if (candles.length > 0) {
|
||||
|
||||
/* On screen candles */
|
||||
let onScreenCandles = []
|
||||
let mouseCandle
|
||||
|
||||
/* Now we calculate all the points. */
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
|
||||
candle = candles[i];
|
||||
|
||||
candle.candlePoint1 = {
|
||||
x: candle.begin + timeFrame / 7 * 1.5,
|
||||
y: candle.open
|
||||
};
|
||||
|
||||
candle.candlePoint2 = {
|
||||
x: candle.begin + timeFrame / 7 * 5.5,
|
||||
y: candle.open
|
||||
};
|
||||
|
||||
candle.candlePoint3 = {
|
||||
x: candle.begin + timeFrame / 7 * 5.5,
|
||||
y: candle.close
|
||||
};
|
||||
|
||||
candle.candlePoint4 = {
|
||||
x: candle.begin + timeFrame / 7 * 1.5,
|
||||
y: candle.close
|
||||
};
|
||||
|
||||
candle.candlePoint1 = coordinateSystem.transformThisPoint(candle.candlePoint1);
|
||||
candle.candlePoint2 = coordinateSystem.transformThisPoint(candle.candlePoint2);
|
||||
candle.candlePoint3 = coordinateSystem.transformThisPoint(candle.candlePoint3);
|
||||
candle.candlePoint4 = coordinateSystem.transformThisPoint(candle.candlePoint4);
|
||||
|
||||
candle.candlePoint1 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(candle.candlePoint1, thisObject.container);
|
||||
candle.candlePoint2 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(candle.candlePoint2, thisObject.container);
|
||||
candle.candlePoint3 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(candle.candlePoint3, thisObject.container);
|
||||
candle.candlePoint4 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(candle.candlePoint4, thisObject.container);
|
||||
|
||||
/* Skip the first candle with zero at open */
|
||||
if (candle.open === 0) { continue }
|
||||
|
||||
if (candle.candlePoint2.x < UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.x || candle.candlePoint1.x > UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.x) {
|
||||
continue
|
||||
}
|
||||
|
||||
addToOnScreenCandles(candle)
|
||||
|
||||
candle.stickPoint1 = {
|
||||
x: candle.begin + timeFrame / 7 * 3.2,
|
||||
y: candle.max
|
||||
};
|
||||
|
||||
candle.stickPoint2 = {
|
||||
x: candle.begin + timeFrame / 7 * 3.8,
|
||||
y: candle.max
|
||||
};
|
||||
|
||||
candle.stickPoint3 = {
|
||||
x: candle.begin + timeFrame / 7 * 3.8,
|
||||
y: candle.min
|
||||
};
|
||||
|
||||
candle.stickPoint4 = {
|
||||
x: candle.begin + timeFrame / 7 * 3.2,
|
||||
y: candle.min
|
||||
};
|
||||
|
||||
candle.stickPoint1 = coordinateSystem.transformThisPoint(candle.stickPoint1);
|
||||
candle.stickPoint2 = coordinateSystem.transformThisPoint(candle.stickPoint2);
|
||||
candle.stickPoint3 = coordinateSystem.transformThisPoint(candle.stickPoint3);
|
||||
candle.stickPoint4 = coordinateSystem.transformThisPoint(candle.stickPoint4);
|
||||
|
||||
candle.stickPoint1 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(candle.stickPoint1, thisObject.container);
|
||||
candle.stickPoint2 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(candle.stickPoint2, thisObject.container);
|
||||
candle.stickPoint3 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(candle.stickPoint3, thisObject.container);
|
||||
candle.stickPoint4 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(candle.stickPoint4, thisObject.container);
|
||||
|
||||
if (UI.projects.superalgos.spaces.chartingSpace.viewport.zoomTargetLevel < UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_PACKING_OBJECTS_AT_THE_BOTTOM_OR_TOP_OF_VIEWPORT) {
|
||||
let diffA = candle.stickPoint3.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.y
|
||||
if (diffA > 0) {
|
||||
candle.candlePoint1.y = candle.candlePoint1.y - diffA
|
||||
candle.candlePoint2.y = candle.candlePoint2.y - diffA
|
||||
candle.candlePoint3.y = candle.candlePoint3.y - diffA
|
||||
candle.candlePoint4.y = candle.candlePoint4.y - diffA
|
||||
|
||||
candle.stickPoint1.y = candle.stickPoint1.y - diffA
|
||||
candle.stickPoint2.y = candle.stickPoint2.y - diffA
|
||||
candle.stickPoint3.y = candle.stickPoint3.y - diffA
|
||||
candle.stickPoint4.y = candle.stickPoint4.y - diffA
|
||||
}
|
||||
|
||||
let diffB = candle.stickPoint1.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.y
|
||||
if (diffB < 0) {
|
||||
candle.candlePoint1.y = candle.candlePoint1.y - diffB
|
||||
candle.candlePoint2.y = candle.candlePoint2.y - diffB
|
||||
candle.candlePoint3.y = candle.candlePoint3.y - diffB
|
||||
candle.candlePoint4.y = candle.candlePoint4.y - diffB
|
||||
|
||||
candle.stickPoint1.y = candle.stickPoint1.y - diffB
|
||||
candle.stickPoint2.y = candle.stickPoint2.y - diffB
|
||||
candle.stickPoint3.y = candle.stickPoint3.y - diffB
|
||||
candle.stickPoint4.y = candle.stickPoint4.y - diffB
|
||||
}
|
||||
}
|
||||
|
||||
candle.candlePoint1 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(candle.candlePoint1);
|
||||
candle.candlePoint2 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(candle.candlePoint2);
|
||||
candle.candlePoint3 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(candle.candlePoint3);
|
||||
candle.candlePoint4 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(candle.candlePoint4);
|
||||
|
||||
candle.candlePoint1 = thisObject.fitFunction(candle.candlePoint1);
|
||||
candle.candlePoint2 = thisObject.fitFunction(candle.candlePoint2);
|
||||
candle.candlePoint3 = thisObject.fitFunction(candle.candlePoint3);
|
||||
candle.candlePoint4 = thisObject.fitFunction(candle.candlePoint4);
|
||||
|
||||
candle.stickPoint1 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(candle.stickPoint1);
|
||||
candle.stickPoint2 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(candle.stickPoint2);
|
||||
candle.stickPoint3 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(candle.stickPoint3);
|
||||
candle.stickPoint4 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(candle.stickPoint4);
|
||||
|
||||
candle.stickPoint1 = thisObject.fitFunction(candle.stickPoint1);
|
||||
candle.stickPoint2 = thisObject.fitFunction(candle.stickPoint2);
|
||||
candle.stickPoint3 = thisObject.fitFunction(candle.stickPoint3);
|
||||
candle.stickPoint4 = thisObject.fitFunction(candle.stickPoint4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function addToOnScreenCandles(candle) {
|
||||
|
||||
/* Contributing to Auto-Scale*/
|
||||
coordinateSystem.reportYValue(candle.max)
|
||||
coordinateSystem.reportYValue(candle.min)
|
||||
|
||||
|
||||
//if (onScreenCandles.length < 15000) {
|
||||
onScreenCandles.push(candle)
|
||||
//}
|
||||
|
||||
if (userPositionDate >= candle.begin && userPositionDate <= candle.end) {
|
||||
mouseCandle = candle
|
||||
}
|
||||
}
|
||||
|
||||
/* We draw the sticks */
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
for (let i = 0; i < onScreenCandles.length; i++) {
|
||||
|
||||
candle = onScreenCandles[i];
|
||||
|
||||
browserCanvasContext.moveTo(candle.stickPoint1.x, candle.stickPoint1.y);
|
||||
browserCanvasContext.lineTo(candle.stickPoint2.x, candle.stickPoint2.y);
|
||||
browserCanvasContext.lineTo(candle.stickPoint3.x, candle.stickPoint3.y);
|
||||
browserCanvasContext.lineTo(candle.stickPoint4.x, candle.stickPoint4.y);
|
||||
}
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (lowResolution === false) {
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', 1)';
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.LIGHT + ', 1)';
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.setLineDash([0, 0])
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
}
|
||||
|
||||
/* The stick at the mouse candle */
|
||||
if (mouseCandle) {
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
candle = mouseCandle
|
||||
|
||||
browserCanvasContext.moveTo(candle.stickPoint1.x, candle.stickPoint1.y);
|
||||
browserCanvasContext.lineTo(candle.stickPoint2.x, candle.stickPoint2.y);
|
||||
browserCanvasContext.lineTo(candle.stickPoint3.x, candle.stickPoint3.y);
|
||||
browserCanvasContext.lineTo(candle.stickPoint4.x, candle.stickPoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (lowResolution === false) {
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', 1)';
|
||||
browserCanvasContext.fill();
|
||||
}
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)';
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.setLineDash([0, 0])
|
||||
browserCanvasContext.stroke();
|
||||
}
|
||||
|
||||
|
||||
/* We draw the candles. */
|
||||
drawCandlesByDirection('up')
|
||||
drawCandlesByDirection('down')
|
||||
drawCandlesByDirection('side')
|
||||
|
||||
function drawCandlesByDirection(direction) {
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
for (let i = 0; i < onScreenCandles.length; i++) {
|
||||
|
||||
candle = onScreenCandles[i];
|
||||
|
||||
if (candle.direction !== direction) { continue }
|
||||
|
||||
browserCanvasContext.moveTo(candle.candlePoint1.x, candle.candlePoint1.y);
|
||||
browserCanvasContext.lineTo(candle.candlePoint2.x, candle.candlePoint2.y);
|
||||
browserCanvasContext.lineTo(candle.candlePoint3.x, candle.candlePoint3.y);
|
||||
browserCanvasContext.lineTo(candle.candlePoint4.x, candle.candlePoint4.y);
|
||||
browserCanvasContext.lineTo(candle.candlePoint1.x, candle.candlePoint1.y);
|
||||
|
||||
elementsPlotted++
|
||||
}
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (lowResolution === false) {
|
||||
|
||||
if (direction === 'up') { browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GREEN + ', 1)'; }
|
||||
if (direction === 'down') { browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', 1)'; }
|
||||
if (direction === 'side') { browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', 1)'; }
|
||||
|
||||
browserCanvasContext.fill();
|
||||
}
|
||||
|
||||
if (direction === 'up') { browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', 1)'; }
|
||||
if (direction === 'down') { browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', 1)'; }
|
||||
if (direction === 'side') { browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.DARK + ', 1)'; }
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.setLineDash([0, 0])
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
}
|
||||
|
||||
/* Draw mouse candel and Raise Event. */
|
||||
if (mouseCandle) {
|
||||
|
||||
/* highlight the current candle */
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
candle = mouseCandle
|
||||
|
||||
browserCanvasContext.moveTo(candle.candlePoint1.x, candle.candlePoint1.y);
|
||||
browserCanvasContext.lineTo(candle.candlePoint2.x, candle.candlePoint2.y);
|
||||
browserCanvasContext.lineTo(candle.candlePoint3.x, candle.candlePoint3.y);
|
||||
browserCanvasContext.lineTo(candle.candlePoint4.x, candle.candlePoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)'; // Current candle accroding to time
|
||||
|
||||
browserCanvasContext.fill();
|
||||
|
||||
let currentCandle = {
|
||||
bodyWidth: candle.candlePoint2.x - candle.candlePoint1.x,
|
||||
bodyHeight: candle.candlePoint3.y - candle.candlePoint2.y,
|
||||
stickHeight: candle.stickPoint4.y - candle.stickPoint2.y,
|
||||
stickWidth: candle.stickPoint2.x - candle.stickPoint1.x,
|
||||
stickStart: candle.candlePoint2.y - candle.stickPoint2.y,
|
||||
period: timeFrame,
|
||||
innerCandle: candle
|
||||
};
|
||||
thisObject.container.eventHandler.raiseEvent("Current Record Changed", currentCandle);
|
||||
}
|
||||
}
|
||||
return elementsPlotted
|
||||
} 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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,256 +0,0 @@
|
||||
|
||||
function newMastersPlottersCandlesVolumesVolumesVolumePanel() {
|
||||
|
||||
let thisObject = {
|
||||
fitFunction: undefined,
|
||||
container: undefined,
|
||||
isVisible: true,
|
||||
onRecordChange: onRecordChange,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
};
|
||||
|
||||
thisObject.container = newContainer();
|
||||
thisObject.container.initialize();
|
||||
thisObject.container.frame.containerName = "Volume";
|
||||
|
||||
let currentVolume;
|
||||
let upDownButton
|
||||
|
||||
return thisObject;
|
||||
|
||||
function finalize() {
|
||||
thisObject.container.finalize()
|
||||
thisObject.container = undefined
|
||||
thisObject.fitFunction = undefined
|
||||
thisObject.isVisible = undefined
|
||||
|
||||
currentVolume = undefined
|
||||
upDownButton.finalize()
|
||||
upDownButton = undefined
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL;
|
||||
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL;
|
||||
|
||||
thisObject.container.frame.position.x = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight.x - thisObject.container.frame.width;
|
||||
thisObject.container.frame.position.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.y - thisObject.container.frame.height;
|
||||
|
||||
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(lastCurrentVolume) {
|
||||
|
||||
currentVolume = lastCurrentVolume;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function draw() {
|
||||
if (thisObject.isVisible !== true) { return }
|
||||
thisObject.container.frame.draw(false, false, true, thisObject.fitFunction);
|
||||
|
||||
plotCurrentVolumeInfo();
|
||||
|
||||
upDownButton.draw()
|
||||
}
|
||||
|
||||
function plotCurrentVolumeInfo() {
|
||||
|
||||
if (currentVolume === undefined) { return; }
|
||||
if (currentVolume.innerVolumeBar === 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_BUY = frameTitleHeight + frameBodyHeight * 0.85;
|
||||
const Y_AXIS_SELL = frameTitleHeight + frameBodyHeight * 0.15;
|
||||
|
||||
let buyVolumePoint1 = {
|
||||
x: X_AXIS - currentVolume.buyInfo.baseWidth / 2,
|
||||
y: Y_AXIS_BUY
|
||||
};
|
||||
|
||||
let buyVolumePoint2 = {
|
||||
x: X_AXIS - currentVolume.buyInfo.topWidth / 2,
|
||||
y: Y_AXIS_BUY + currentVolume.buyInfo.height
|
||||
};
|
||||
|
||||
let buyVolumePoint3 = {
|
||||
x: X_AXIS + currentVolume.buyInfo.topWidth / 2,
|
||||
y: Y_AXIS_BUY + currentVolume.buyInfo.height
|
||||
};
|
||||
|
||||
let buyVolumePoint4 = {
|
||||
x: X_AXIS + currentVolume.buyInfo.baseWidth / 2,
|
||||
y: Y_AXIS_BUY
|
||||
};
|
||||
|
||||
/* Extra bounderies due to constrained space */
|
||||
|
||||
const upperLimit = frameTitleHeight + frameBodyHeight * 0.15;
|
||||
const downLimit = frameTitleHeight + frameBodyHeight * 0.85;
|
||||
|
||||
const leftLimit = thisObject.container.frame.width * 0.40;
|
||||
const rightLimit = thisObject.container.frame.width * 0.60;
|
||||
|
||||
if (buyVolumePoint1.y < downLimit) { buyVolumePoint1.y = downLimit; }
|
||||
if (buyVolumePoint4.y < downLimit) { buyVolumePoint4.y = downLimit; }
|
||||
|
||||
if (buyVolumePoint2.y < upperLimit) { buyVolumePoint2.y = upperLimit; }
|
||||
if (buyVolumePoint3.y < upperLimit) { buyVolumePoint3.y = upperLimit; }
|
||||
|
||||
if (buyVolumePoint1.x < leftLimit) { buyVolumePoint1.x = leftLimit; }
|
||||
if (buyVolumePoint2.x < leftLimit) { buyVolumePoint2.x = leftLimit; }
|
||||
|
||||
if (buyVolumePoint3.x > rightLimit) { buyVolumePoint3.x = rightLimit; }
|
||||
if (buyVolumePoint4.x > rightLimit) { buyVolumePoint4.x = rightLimit; }
|
||||
|
||||
|
||||
|
||||
buyVolumePoint1 = thisObject.container.frame.fitIntoFrame(buyVolumePoint1);
|
||||
buyVolumePoint2 = thisObject.container.frame.fitIntoFrame(buyVolumePoint2);
|
||||
buyVolumePoint3 = thisObject.container.frame.fitIntoFrame(buyVolumePoint3);
|
||||
buyVolumePoint4 = thisObject.container.frame.fitIntoFrame(buyVolumePoint4);
|
||||
|
||||
buyVolumePoint1 = thisObject.container.frame.frameThisPoint(buyVolumePoint1);
|
||||
buyVolumePoint2 = thisObject.container.frame.frameThisPoint(buyVolumePoint2);
|
||||
buyVolumePoint3 = thisObject.container.frame.frameThisPoint(buyVolumePoint3);
|
||||
buyVolumePoint4 = thisObject.container.frame.frameThisPoint(buyVolumePoint4);
|
||||
|
||||
buyVolumePoint1 = thisObject.fitFunction(buyVolumePoint1)
|
||||
buyVolumePoint2 = thisObject.fitFunction(buyVolumePoint2)
|
||||
buyVolumePoint3 = thisObject.fitFunction(buyVolumePoint3)
|
||||
buyVolumePoint4 = thisObject.fitFunction(buyVolumePoint4)
|
||||
|
||||
let sellVolumePoint1 = {
|
||||
x: X_AXIS - currentVolume.buyInfo.baseWidth / 2,
|
||||
y: Y_AXIS_SELL
|
||||
};
|
||||
|
||||
let sellVolumePoint2 = {
|
||||
x: X_AXIS - currentVolume.buyInfo.topWidth / 2,
|
||||
y: Y_AXIS_SELL + currentVolume.sellInfo.height
|
||||
};
|
||||
|
||||
let sellVolumePoint3 = {
|
||||
x: X_AXIS + currentVolume.buyInfo.topWidth / 2,
|
||||
y: Y_AXIS_SELL + currentVolume.sellInfo.height
|
||||
};
|
||||
|
||||
let sellVolumePoint4 = {
|
||||
x: X_AXIS + currentVolume.buyInfo.baseWidth / 2,
|
||||
y: Y_AXIS_SELL
|
||||
};
|
||||
|
||||
if (sellVolumePoint1.y < upperLimit) { sellVolumePoint1.y = upperLimit; }
|
||||
if (sellVolumePoint4.y < upperLimit) { sellVolumePoint4.y = upperLimit; }
|
||||
|
||||
if (sellVolumePoint2.y > downLimit) { sellVolumePoint2.y = downLimit; }
|
||||
if (sellVolumePoint3.y > downLimit) { sellVolumePoint3.y = downLimit; }
|
||||
|
||||
if (sellVolumePoint1.x < leftLimit) { sellVolumePoint1.x = leftLimit; }
|
||||
if (sellVolumePoint2.x < leftLimit) { sellVolumePoint2.x = leftLimit; }
|
||||
|
||||
if (sellVolumePoint3.x > rightLimit) { sellVolumePoint3.x = rightLimit; }
|
||||
if (sellVolumePoint4.x > rightLimit) { sellVolumePoint4.x = rightLimit; }
|
||||
|
||||
sellVolumePoint1 = thisObject.container.frame.fitIntoFrame(sellVolumePoint1);
|
||||
sellVolumePoint2 = thisObject.container.frame.fitIntoFrame(sellVolumePoint2);
|
||||
sellVolumePoint3 = thisObject.container.frame.fitIntoFrame(sellVolumePoint3);
|
||||
sellVolumePoint4 = thisObject.container.frame.fitIntoFrame(sellVolumePoint4);
|
||||
|
||||
sellVolumePoint1 = thisObject.container.frame.frameThisPoint(sellVolumePoint1);
|
||||
sellVolumePoint2 = thisObject.container.frame.frameThisPoint(sellVolumePoint2);
|
||||
sellVolumePoint3 = thisObject.container.frame.frameThisPoint(sellVolumePoint3);
|
||||
sellVolumePoint4 = thisObject.container.frame.frameThisPoint(sellVolumePoint4);
|
||||
|
||||
sellVolumePoint1 = thisObject.fitFunction(sellVolumePoint1)
|
||||
sellVolumePoint2 = thisObject.fitFunction(sellVolumePoint2)
|
||||
sellVolumePoint3 = thisObject.fitFunction(sellVolumePoint3)
|
||||
sellVolumePoint4 = thisObject.fitFunction(sellVolumePoint4)
|
||||
|
||||
|
||||
|
||||
const OPACITY = '0.40';
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(buyVolumePoint1.x, buyVolumePoint1.y);
|
||||
browserCanvasContext.lineTo(buyVolumePoint2.x, buyVolumePoint2.y);
|
||||
browserCanvasContext.lineTo(buyVolumePoint3.x, buyVolumePoint3.y);
|
||||
browserCanvasContext.lineTo(buyVolumePoint4.x, buyVolumePoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + OPACITY + ')';
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + OPACITY + ')';
|
||||
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(sellVolumePoint1.x, sellVolumePoint1.y);
|
||||
browserCanvasContext.lineTo(sellVolumePoint2.x, sellVolumePoint2.y);
|
||||
browserCanvasContext.lineTo(sellVolumePoint3.x, sellVolumePoint3.y);
|
||||
browserCanvasContext.lineTo(sellVolumePoint4.x, sellVolumePoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + OPACITY + ')';
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + OPACITY + ')';
|
||||
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
/* put the labels with the volumes values */
|
||||
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel('Buy Volume', undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.95, '0.60', undefined, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel(currentVolume.innerVolumeBar.amountBuy, undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.90, '1.00', 15, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel('Sell Volume', undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.05, '0.60', undefined, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
UI.projects.superalgos.utilities.drawPrint.printLabel(currentVolume.innerVolumeBar.amountSell, undefined, undefined, X_AXIS, frameTitleHeight + frameBodyHeight * 0.10, '1.00', 15, undefined, 'Center', thisObject.container, thisObject.fitFunction);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,755 +0,0 @@
|
||||
function newMastersPlottersCandlesVolumesVolumes() {
|
||||
|
||||
const MODULE_NAME = "Volumes Plotter";
|
||||
const ERROR_LOG = true;
|
||||
const INTENSIVE_LOG = false;
|
||||
const logger = newWebDebugLog();
|
||||
logger.fileName = MODULE_NAME;
|
||||
|
||||
let thisObject = {
|
||||
|
||||
/* Events declared outside the plotter. */
|
||||
|
||||
onDailyFileLoaded: onDailyFileLoaded,
|
||||
|
||||
// Main functions and properties.
|
||||
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
container: undefined,
|
||||
fitFunction: undefined,
|
||||
getContainer: getContainer,
|
||||
setTimeFrame: setTimeFrame,
|
||||
setDatetime: setDatetime,
|
||||
setCoordinateSystem: setCoordinateSystem,
|
||||
recalculateScale: recalculateScale,
|
||||
draw: draw
|
||||
};
|
||||
|
||||
/* this is part of the module template */
|
||||
|
||||
thisObject.container = newContainer()
|
||||
thisObject.container.initialize(MODULE_NAME)
|
||||
|
||||
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.
|
||||
|
||||
let scaleFile; // This file is used to calculate the scale.
|
||||
|
||||
/* these are module specific variables: */
|
||||
|
||||
let volumes = []; // Here we keep the volumes to be ploted every time the Draw() function is called by the AAWebPlatform.
|
||||
|
||||
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)
|
||||
UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.stopListening(zoomChangedEventSubscriptionId);
|
||||
UI.projects.superalgos.spaces.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 {
|
||||
|
||||
/* 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. */
|
||||
|
||||
scaleFile = 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 = UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.listenToEvent("Zoom Changed", onViewportZoomChanged);
|
||||
offsetChangedEventSubscriptionId = UI.projects.superalgos.spaces.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();
|
||||
|
||||
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 = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(event, thisObject.container, coordinateSystem)
|
||||
userPositionDate = userPosition.valueOf()
|
||||
}
|
||||
|
||||
function recalculateScale() {
|
||||
recalculate();
|
||||
}
|
||||
|
||||
function getContainer(point) {
|
||||
|
||||
try {
|
||||
|
||||
let container;
|
||||
|
||||
/* First we check if this point is inside this space. */
|
||||
|
||||
if (thisObject.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return thisObject.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) {
|
||||
|
||||
let newMarketFile = marketFiles.getFile(pTimeFrame);
|
||||
|
||||
if (newMarketFile !== undefined) {
|
||||
|
||||
marketFile = newMarketFile;
|
||||
recalculate();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
let newFileCursor = dailyFiles.getFileCursor(pTimeFrame);
|
||||
|
||||
if (newFileCursor !== undefined) {
|
||||
|
||||
fileCursor = newFileCursor;
|
||||
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) {
|
||||
|
||||
if (event.currentValue === event.totalValue) {
|
||||
/* This happens only when all of the files in the cursor have been loaded. */
|
||||
recalculate();
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
|
||||
try {
|
||||
|
||||
if (INTENSIVE_LOG === true) { logger.write("[INFO] draw -> Entering function."); }
|
||||
|
||||
thisObject.container.frame.draw();
|
||||
|
||||
plotChart();
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] draw -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function recalculate() {
|
||||
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
|
||||
recalculateUsingMarketFiles();
|
||||
} else {
|
||||
recalculateUsingDailyFiles();
|
||||
}
|
||||
thisObject.container.eventHandler.raiseEvent("Volumes Changed", volumes);
|
||||
}
|
||||
|
||||
function recalculateUsingDailyFiles() {
|
||||
|
||||
try {
|
||||
|
||||
if (fileCursor === undefined) { return; } // We need to wait
|
||||
|
||||
if (fileCursor.files.size === 0) { return; } // We need to wait until there are files in the cursor
|
||||
|
||||
let leftDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
|
||||
let rightDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.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());
|
||||
|
||||
volumes = [];
|
||||
|
||||
while (currentDate.valueOf() <= farRightDate.valueOf() + ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
let stringDate = currentDate.getUTCFullYear() + '-' + pad(currentDate.getUTCMonth() + 1, 2) + '-' + pad(currentDate.getUTCDate(), 2);
|
||||
|
||||
let dailyFile = fileCursor.files.get(stringDate);
|
||||
|
||||
if (dailyFile !== undefined) {
|
||||
|
||||
for (let i = 0; i < dailyFile.length; i++) {
|
||||
|
||||
let volume = {
|
||||
amountBuy: 0,
|
||||
amountSell: 0,
|
||||
begin: undefined,
|
||||
end: undefined
|
||||
};
|
||||
|
||||
volume.amountBuy = dailyFile[i][0];
|
||||
volume.amountSell = dailyFile[i][1];
|
||||
|
||||
volume.begin = dailyFile[i][2];
|
||||
volume.end = dailyFile[i][3];
|
||||
|
||||
if (
|
||||
(volume.begin >= farLeftDate.valueOf() && volume.end <= farRightDate.valueOf()) &&
|
||||
(volume.begin >= coordinateSystem.min.x && volume.end <= coordinateSystem.max.x)
|
||||
) {
|
||||
|
||||
volumes.push(volume);
|
||||
|
||||
if (datetime.valueOf() >= volume.begin && datetime.valueOf() <= volume.end) {
|
||||
|
||||
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.currentCandle);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS);
|
||||
}
|
||||
|
||||
/* Lests check if all the visible screen is going to be covered by volumes. */
|
||||
|
||||
let lowerEnd = leftDate.valueOf();
|
||||
let upperEnd = rightDate.valueOf();
|
||||
|
||||
if (volumes.length > 0) {
|
||||
|
||||
if (volumes[0].begin > lowerEnd || volumes[volumes.length - 1].end < upperEnd) {
|
||||
|
||||
setTimeout(recalculate, 2000);
|
||||
|
||||
//console.log("File missing while calculating volumes, scheduling a recalculation in 2 seconds.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//console.log("Olivia > recalculateUsingDailyFiles > total volumes generated : " + volumes.length);
|
||||
|
||||
} 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 leftDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem);
|
||||
let rightDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.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);
|
||||
|
||||
volumes = [];
|
||||
|
||||
for (let i = 0; i < marketFile.length; i++) {
|
||||
|
||||
let volume = {
|
||||
amountBuy: 0,
|
||||
amountSell: 0,
|
||||
begin: undefined,
|
||||
end: undefined
|
||||
};
|
||||
|
||||
volume.amountBuy = marketFile[i][0];
|
||||
volume.amountSell = marketFile[i][1];
|
||||
|
||||
volume.begin = marketFile[i][2];
|
||||
volume.end = marketFile[i][3];
|
||||
|
||||
if (
|
||||
(volume.begin >= leftDate.valueOf() && volume.end <= rightDate.valueOf()) &&
|
||||
(volume.begin >= coordinateSystem.min.x && volume.end <= coordinateSystem.max.x)
|
||||
) {
|
||||
|
||||
volumes.push(volume);
|
||||
|
||||
if (datetime.valueOf() >= volume.begin && datetime.valueOf() <= volume.end) {
|
||||
|
||||
thisObject.container.eventHandler.raiseEvent("Current Record Changed", thisObject.currentCandle);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//console.log("Olivia > recalculateUsingMarketFiles > total volumes generated : " + volumes.length);
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingMarketFiles -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function plotChart() {
|
||||
|
||||
try {
|
||||
|
||||
let lowResolution = false
|
||||
if (UI.projects.superalgos.spaces.chartingSpace.viewport.zoomTargetLevel < UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_PLOTTING_IN_LOW_RESOLUTION) {
|
||||
if (volumes.length > 100) {
|
||||
lowResolution = true
|
||||
}
|
||||
}
|
||||
|
||||
if (volumes.length > 0) {
|
||||
|
||||
/* Now we calculate and plot the volumes */
|
||||
|
||||
let visibleHeight = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.y;
|
||||
|
||||
let frameCorner1 = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
|
||||
let frameCorner2 = {
|
||||
x: thisObject.container.frame.width,
|
||||
y: thisObject.container.frame.height
|
||||
};
|
||||
|
||||
|
||||
/* Now the transformations. */
|
||||
|
||||
frameCorner1 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(frameCorner1, thisObject.container.frame.container);
|
||||
frameCorner2 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(frameCorner2, thisObject.container.frame.container);
|
||||
|
||||
let frameHeightInViewPort = frameCorner2.y - frameCorner1.y;
|
||||
|
||||
if (volumes.length > 0) {
|
||||
|
||||
for (let i = 0; i < volumes.length; i++) {
|
||||
|
||||
volume = volumes[i];
|
||||
|
||||
let volumePointA1;
|
||||
let volumePointA2;
|
||||
let volumePointA3;
|
||||
let volumePointA4;
|
||||
|
||||
function calculateBuys(plot, height) {
|
||||
|
||||
volumePointA1 = {
|
||||
x: volume.begin + timeFrame / 7 * 2,
|
||||
y: 0
|
||||
};
|
||||
|
||||
volumePointA2 = {
|
||||
x: volume.begin + timeFrame / 7 * 2,
|
||||
y: volume.amountBuy
|
||||
};
|
||||
|
||||
volumePointA3 = {
|
||||
x: volume.begin + timeFrame / 7 * 5,
|
||||
y: volume.amountBuy
|
||||
};
|
||||
|
||||
volumePointA4 = {
|
||||
x: volume.begin + timeFrame / 7 * 5,
|
||||
y: 0
|
||||
};
|
||||
|
||||
volumePointA1 = plot.transformThisPoint(volumePointA1);
|
||||
volumePointA2 = plot.transformThisPoint(volumePointA2);
|
||||
volumePointA3 = plot.transformThisPoint(volumePointA3);
|
||||
volumePointA4 = plot.transformThisPoint(volumePointA4);
|
||||
|
||||
volumePointA1 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(volumePointA1, thisObject.container);
|
||||
volumePointA2 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(volumePointA2, thisObject.container);
|
||||
volumePointA3 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(volumePointA3, thisObject.container);
|
||||
volumePointA4 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(volumePointA4, thisObject.container);
|
||||
|
||||
let baseIncrement = (volumePointA3.x - volumePointA1.x) * WIDHTER_VOLUME_BAR_BASE_FACTOR;
|
||||
|
||||
volumePointA1.x = volumePointA1.x - baseIncrement;
|
||||
volumePointA4.x = volumePointA4.x + baseIncrement;
|
||||
|
||||
if (volumePointA4.x < UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.x || volumePointA1.x > UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
if (calculateBuys(coordinateSystem, thisObject.container.frame.height) === false) { continue; } // We try to see if it fits in the visible area.
|
||||
|
||||
let diffA = volumePointA1.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.y
|
||||
if (diffA > 0) {
|
||||
volumePointA1.y = volumePointA1.y - diffA
|
||||
volumePointA2.y = volumePointA2.y - diffA
|
||||
volumePointA3.y = volumePointA3.y - diffA
|
||||
volumePointA4.y = volumePointA4.y - diffA
|
||||
}
|
||||
|
||||
let volumePointB1;
|
||||
let volumePointB2;
|
||||
let volumePointB3;
|
||||
let volumePointB4;
|
||||
|
||||
function calculateSells(plot, height) {
|
||||
|
||||
volumePointB1 = {
|
||||
x: volume.begin + timeFrame / 7 * 2,
|
||||
y: height
|
||||
};
|
||||
|
||||
volumePointB2 = {
|
||||
x: volume.begin + timeFrame / 7 * 2,
|
||||
y: height - volume.amountSell
|
||||
};
|
||||
|
||||
volumePointB3 = {
|
||||
x: volume.begin + timeFrame / 7 * 5,
|
||||
y: height - volume.amountSell
|
||||
};
|
||||
|
||||
volumePointB4 = {
|
||||
x: volume.begin + timeFrame / 7 * 5,
|
||||
y: height
|
||||
};
|
||||
|
||||
volumePointB1 = plot.transformThisPoint2(volumePointB1);
|
||||
volumePointB2 = plot.transformThisPoint2(volumePointB2);
|
||||
volumePointB3 = plot.transformThisPoint2(volumePointB3);
|
||||
volumePointB4 = plot.transformThisPoint2(volumePointB4);
|
||||
|
||||
volumePointB1 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(volumePointB1, thisObject.container);
|
||||
volumePointB2 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(volumePointB2, thisObject.container);
|
||||
volumePointB3 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(volumePointB3, thisObject.container);
|
||||
volumePointB4 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(volumePointB4, thisObject.container);
|
||||
}
|
||||
|
||||
calculateSells(coordinateSystem, thisObject.container.frame.height); // We try to see if it fits in the visible area.
|
||||
|
||||
let diffB = volumePointB1.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.y
|
||||
if (diffB < 0) {
|
||||
volumePointB1.y = volumePointB1.y - diffB
|
||||
volumePointB2.y = volumePointB2.y - diffB
|
||||
volumePointB3.y = volumePointB3.y - diffB
|
||||
volumePointB4.y = volumePointB4.y - diffB
|
||||
}
|
||||
|
||||
/* We put a wider base */
|
||||
|
||||
let baseIncrement = (volumePointB3.x - volumePointB1.x) * WIDHTER_VOLUME_BAR_BASE_FACTOR;
|
||||
|
||||
volumePointB1.x = volumePointB1.x - baseIncrement;
|
||||
volumePointB4.x = volumePointB4.x + baseIncrement;
|
||||
|
||||
/* We put a less wider top */
|
||||
|
||||
let baseDencrement = (volumePointA3.x - volumePointA2.x) * LESS_WIDHTER_VOLUME_BAR_TOP_FACTOR;
|
||||
|
||||
volumePointA2.x = volumePointA2.x + baseDencrement;
|
||||
volumePointA3.x = volumePointA3.x - baseDencrement;
|
||||
|
||||
volumePointB2.x = volumePointB2.x + baseDencrement;
|
||||
volumePointB3.x = volumePointB3.x - baseDencrement;
|
||||
|
||||
|
||||
/* Everything must fit within the visible area */
|
||||
|
||||
volumePointA1 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(volumePointA1);
|
||||
volumePointA2 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(volumePointA2);
|
||||
volumePointA3 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(volumePointA3);
|
||||
volumePointA4 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(volumePointA4);
|
||||
|
||||
volumePointB1 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(volumePointB1);
|
||||
volumePointB2 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(volumePointB2);
|
||||
volumePointB3 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(volumePointB3);
|
||||
volumePointB4 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(volumePointB4);
|
||||
|
||||
volumePointA1 = thisObject.fitFunction(volumePointA1);
|
||||
volumePointA2 = thisObject.fitFunction(volumePointA2);
|
||||
volumePointA3 = thisObject.fitFunction(volumePointA3);
|
||||
volumePointA4 = thisObject.fitFunction(volumePointA4);
|
||||
|
||||
volumePointB1 = thisObject.fitFunction(volumePointB1);
|
||||
volumePointB2 = thisObject.fitFunction(volumePointB2);
|
||||
volumePointB3 = thisObject.fitFunction(volumePointB3);
|
||||
volumePointB4 = thisObject.fitFunction(volumePointB4);
|
||||
|
||||
/* Everything must fit within the Frame. We know that that is equivalent to say that each bar con not be higher than the base of the opposite . */
|
||||
|
||||
if (volumePointA2.y < volumePointB1.y) {
|
||||
|
||||
volumePointA2.y = volumePointB1.y;
|
||||
volumePointA3.y = volumePointB1.y;
|
||||
|
||||
}
|
||||
|
||||
if (volumePointB2.y > volumePointA1.y) {
|
||||
|
||||
volumePointB2.y = volumePointA1.y;
|
||||
volumePointB3.y = volumePointA1.y;
|
||||
|
||||
}
|
||||
|
||||
/* Now the drawing of the volume bars*/
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(volumePointA1.x, volumePointA1.y);
|
||||
browserCanvasContext.lineTo(volumePointA2.x, volumePointA2.y);
|
||||
browserCanvasContext.lineTo(volumePointA3.x, volumePointA3.y);
|
||||
browserCanvasContext.lineTo(volumePointA4.x, volumePointA4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (lowResolution === false) {
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GREEN + ', 0.40)';
|
||||
|
||||
if (userPositionDate >= volume.begin && userPositionDate <= volume.end) {
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 0.40)'; // Current bar accroding to time
|
||||
}
|
||||
}
|
||||
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', 0.40)';
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.setLineDash([0, 0])
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(volumePointB1.x, volumePointB1.y);
|
||||
browserCanvasContext.lineTo(volumePointB2.x, volumePointB2.y);
|
||||
browserCanvasContext.lineTo(volumePointB3.x, volumePointB3.y);
|
||||
browserCanvasContext.lineTo(volumePointB4.x, volumePointB4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (lowResolution === false) {
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', 0.40)';
|
||||
|
||||
if (userPositionDate >= volume.begin && userPositionDate <= volume.end) {
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 0.40)'; // Current volume accroding to time
|
||||
}
|
||||
|
||||
browserCanvasContext.fill();
|
||||
}
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', 0.40)';
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.setLineDash([0, 0])
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
if (userPositionDate >= volume.begin && userPositionDate <= volume.end) {
|
||||
|
||||
let buyInfo = {
|
||||
baseWidth: volumePointA4.x - volumePointA1.x,
|
||||
topWidth: volumePointA3.x - volumePointA2.x,
|
||||
height: volumePointA2.y - volumePointA1.y
|
||||
};
|
||||
|
||||
let sellInfo = {
|
||||
baseWidth: volumePointB4.x - volumePointB1.x,
|
||||
topWidth: volumePointB3.x - volumePointB2.x,
|
||||
height: volumePointB2.y - volumePointB1.y
|
||||
};
|
||||
|
||||
let currentVolume = {
|
||||
buyInfo: buyInfo,
|
||||
sellInfo: sellInfo,
|
||||
period: timeFrame,
|
||||
innerVolumeBar: volume
|
||||
};
|
||||
|
||||
thisObject.container.eventHandler.raiseEvent("Current Record Changed", currentVolume);
|
||||
|
||||
}
|
||||
/* Contributing to Auto-Scale*/
|
||||
coordinateSystem.reportYValue(volume.amountBuy * 5)
|
||||
coordinateSystem.reportYValue(volume.amountSell * 5)
|
||||
coordinateSystem.reportYValue(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (ERROR_LOG === true) { logger.write("[ERROR] plotChart -> err = " + err.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
function onViewportZoomChanged(event) {
|
||||
recalculate()
|
||||
}
|
||||
|
||||
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() {
|
||||
recalculate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"displayName": "Plotters Candles & Volumes",
|
||||
"codeName": "PlottersCandlesVolumes",
|
||||
"dataMine": "Masters",
|
||||
"modules": [
|
||||
{
|
||||
"codeName": "Candles",
|
||||
"moduleName": "Candles",
|
||||
"description": "Plots traditional red and green candles.",
|
||||
"profilePicture": "Candles.png",
|
||||
"panels": [
|
||||
{
|
||||
"codeName": "CandlePanel",
|
||||
"moduleName": "CandlePanel",
|
||||
"event": "Current Record Changed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"codeName": "Volumes",
|
||||
"description": "Plots volumes separated in buy and sell.",
|
||||
"moduleName": "Volumes",
|
||||
"profilePicture": "Volumes.png",
|
||||
"panels": [
|
||||
{
|
||||
"codeName": "VolumePanel",
|
||||
"moduleName": "VolumePanel",
|
||||
"event": "Current Record Changed"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user