Old Proof Of Concept Stuff deleted
This commit is contained in:
1 parent
f0d0803848
commit
3b92a293a6
22 files changed
+23
-5665
No files matched your search
Binary file not shown.
@@ -56,23 +56,8 @@
|
||||
</Compile>
|
||||
<Compile Include="Button.js" />
|
||||
<Compile Include="Candle.js" />
|
||||
<Compile Include="CandleTechnicalAnalisys\HighLowFlag.js" />
|
||||
<Compile Include="CandleTechnicalAnalisys\Resistance.js" />
|
||||
<Compile Include="CandleTechnicalAnalisys\Stairs.js" />
|
||||
<Compile Include="CandleTechnicalAnalisys\Support.js" />
|
||||
<Compile Include="Canvas.js" />
|
||||
<Compile Include="ChartGrid.js" />
|
||||
<Compile Include="ChartLayers\AccumulatedVolumeChartLayer.js" />
|
||||
<Compile Include="ChartLayers\AllTimeChartlayer.js" />
|
||||
<Compile Include="ChartLayers\CandeStickChartLayer.js" />
|
||||
<Compile Include="ChartLayers\CandleTechnicalAnalisysChartLayer.js" />
|
||||
<Compile Include="ChartLayers\ForecastChartLayer.js" />
|
||||
<Compile Include="ChartLayers\HighLowChartLayer.js" />
|
||||
<Compile Include="ChartLayers\LinearRegressionCurve.js" />
|
||||
<Compile Include="ChartLayers\OrderBooksChartLayer.js" />
|
||||
<Compile Include="ChartLayers\SupportResistanceChartLayer.js" />
|
||||
<Compile Include="ChartLayers\VolumeChartLayer.js" />
|
||||
<Compile Include="ChartLayers\VolumeTechnicalAnalisysChartLayer.js" />
|
||||
<Compile Include="ChartSpace.js" />
|
||||
<Compile Include="ChartUtilities.js" />
|
||||
<Compile Include="Container.js" />
|
||||
@@ -89,7 +74,6 @@
|
||||
<Compile Include="EventHandler.js" />
|
||||
<Compile Include="FloatingSpace.js" />
|
||||
<Compile Include="Frame.js" />
|
||||
<Compile Include="Indicators\LRC.js" />
|
||||
<Compile Include="MarketIndex.js" />
|
||||
<Compile Include="Markets.js" />
|
||||
<Compile Include="MarketTrades.js" />
|
||||
@@ -128,7 +112,6 @@
|
||||
<Compile Include="Utilities.js" />
|
||||
<Compile Include="ViewPort.js" />
|
||||
<Compile Include="VolumeBar.js" />
|
||||
<Compile Include="VolumeTechnicalAnalisys\Stairs.js" />
|
||||
<Compile Include="Zoom.js" />
|
||||
<Content Include="ecosystem.json">
|
||||
<SubType>Code</SubType>
|
||||
@@ -139,11 +122,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Azure\" />
|
||||
<Folder Include="CandleTechnicalAnalisys\" />
|
||||
<Folder Include="ChartLayers\" />
|
||||
<Folder Include="Indicators\" />
|
||||
<Folder Include="Panels\" />
|
||||
<Folder Include="VolumeTechnicalAnalisys\" />
|
||||
</ItemGroup>
|
||||
<!-- Do not delete the following Import Project. While this appears to do nothing it is a marker for setting TypeScript properties before our import that depends on them. -->
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" Condition="False" />
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
function newHighLowFlag() {
|
||||
|
||||
var highLowFlag = {
|
||||
rate: undefined,
|
||||
type: undefined,
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
firstBegin: undefined,
|
||||
lastEnd: undefined,
|
||||
pastCandles: 0,
|
||||
futureCandles: 0
|
||||
};
|
||||
|
||||
return highLowFlag;
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
function newResistance() {
|
||||
|
||||
var resistance = {
|
||||
rate: undefined,
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
candleCount: 0
|
||||
};
|
||||
|
||||
return resistance;
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
function newCandleStairs() {
|
||||
|
||||
var candleStairs = {
|
||||
open: undefined,
|
||||
close: undefined,
|
||||
min: 10000000000000,
|
||||
max: 0,
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
direction: undefined,
|
||||
candleCount: 0,
|
||||
firstMin: 0,
|
||||
firstMax: 0,
|
||||
lastMin: 0,
|
||||
lastMax: 0,
|
||||
slope: undefined
|
||||
};
|
||||
|
||||
return candleStairs;
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
function newSupport() {
|
||||
|
||||
var support = {
|
||||
rate: undefined,
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
candleCount: 0
|
||||
};
|
||||
|
||||
return support;
|
||||
|
||||
}
|
||||
@@ -1,672 +0,0 @@
|
||||
|
||||
function newAccumulatedVolumeChartLayer() {
|
||||
|
||||
|
||||
var volumeBars = [];
|
||||
let timePeriod = INITIAL_TIME_PERIOD;
|
||||
|
||||
var plotArea = newPlotArea();
|
||||
var plotAreaFrame = newPlotArea();
|
||||
|
||||
let datetime = INITIAL_DATE;
|
||||
|
||||
var accumulatedVolumeChartLayer = {
|
||||
onLayerStatusChanged: onLayerStatusChanged,
|
||||
setTimePeriod: setTimePeriod,
|
||||
setDatetime: setDatetime,
|
||||
container: undefined,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
var container = newContainer();
|
||||
container.initialize();
|
||||
accumulatedVolumeChartLayer.container = container;
|
||||
|
||||
container.displacement.containerName = "Accumulated Volume Chart";
|
||||
container.zoom.containerName = "Accumulated Volume Chart";
|
||||
container.frame.containerName = "Accumulated Volume Chart";
|
||||
|
||||
var marketId;
|
||||
var exchangeId;
|
||||
|
||||
let marketIndex;
|
||||
let dailyFilesCursor;
|
||||
|
||||
let maxAccumulatedBalance = 0;
|
||||
const MAX_ACCUMULATED_BALANCE_BARS_HEIGHT = 250;
|
||||
const PLOT_Y_BASE_LINE = viewPort.visibleArea.bottomLeft.y * 0.50;
|
||||
|
||||
let layerStatus = 'off';
|
||||
let parentLayerStatus = 'off';
|
||||
|
||||
return accumulatedVolumeChartLayer;
|
||||
|
||||
function initialize(exchange, market, index, dailyFiles, botsPanel) {
|
||||
|
||||
marketId = market;
|
||||
exchangeId = exchange;
|
||||
|
||||
marketIndex = index;
|
||||
dailyFilesCursor = dailyFiles;
|
||||
|
||||
recalculateScaleX();
|
||||
recalculateVolumeBars();
|
||||
recalculateScaleY();
|
||||
|
||||
viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged);
|
||||
canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished);
|
||||
|
||||
layerStatus = botsPanel.getProductStatus(botsPanel.layerNames.BUY_SELL_BALANCE);
|
||||
parentLayerStatus = botsPanel.getProductStatus(botsPanel.layerNames.VOLUME);
|
||||
|
||||
}
|
||||
|
||||
function getContainer(point) {
|
||||
|
||||
if (layerStatus === 'off') { return; }
|
||||
|
||||
var container;
|
||||
|
||||
/* First we check if this point is inside this space. */
|
||||
|
||||
if (this.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return this.container;
|
||||
|
||||
} else {
|
||||
|
||||
/* This point does not belong to this space. */
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function onLayerStatusChanged(eventData) {
|
||||
|
||||
if (eventData.layer === 'Volume') {
|
||||
parentLayerStatus = eventData.status;
|
||||
}
|
||||
|
||||
if (eventData.layer === 'Buy Sell Balance') {
|
||||
layerStatus = eventData.status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onZoomChanged(event) {
|
||||
|
||||
recalculateScaleX();
|
||||
recalculateVolumeBars();
|
||||
recalculateScaleY();
|
||||
|
||||
}
|
||||
|
||||
function onDragFinished() {
|
||||
|
||||
|
||||
if (timePeriod !== ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
recalculateScaleX();
|
||||
recalculateVolumeBars();
|
||||
recalculateScaleY();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function setTimePeriod(period) {
|
||||
|
||||
timePeriod = period;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function setDatetime(newDatetime) {
|
||||
datetime = newDatetime;
|
||||
recalculateVolumeBars();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
if (layerStatus !== 'on') { return; }
|
||||
|
||||
if (parentLayerStatus === 'off') { return; }
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
if (timePeriod !== ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
if (Math.random() * 100 > 98) {
|
||||
recalculateScaleX();
|
||||
recalculateVolumeBars();
|
||||
recalculateScaleY();
|
||||
}
|
||||
}
|
||||
|
||||
plotAccumulatedVolumeBalanceChart();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateVolumeBars() {
|
||||
|
||||
if (layerStatus === 'off') { return; }
|
||||
|
||||
if (parentLayerStatus === 'off') { return; }
|
||||
|
||||
if (timePeriod === ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
recalculateVolumeBarsUsingMarketIndex();
|
||||
|
||||
} else {
|
||||
|
||||
recalculateVolumeBarsUsingDailyFiles();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateVolumeBarsUsingMarketIndex() {
|
||||
|
||||
volumeBars = [];
|
||||
|
||||
let accumulatedBuys = 0;
|
||||
let accumulatedSells = 0;
|
||||
maxAccumulatedBalance = 0;
|
||||
|
||||
|
||||
for (var i = 0; i < marketIndex.volumes.length; i++) {
|
||||
|
||||
var volumeBar = newAccumulatedVolumeBar();
|
||||
|
||||
let amountBuy = 0;
|
||||
let amountSell = 0;
|
||||
|
||||
volumeBar.begin = (new Date(marketIndex.volumes[i][2])).valueOf();
|
||||
volumeBar.end = (new Date(marketIndex.volumes[i][3])).valueOf();
|
||||
|
||||
amountBuy = marketIndex.volumes[i][0];
|
||||
amountSell = marketIndex.volumes[i][1];
|
||||
|
||||
accumulatedBuys = accumulatedBuys + amountBuy;
|
||||
accumulatedSells = accumulatedSells + amountSell;
|
||||
|
||||
volumeBar.accumulatedBuys = accumulatedBuys;
|
||||
volumeBar.accumulatedSells = accumulatedSells;
|
||||
|
||||
let balance = volumeBar.accumulatedBuys - volumeBar.accumulatedSells;
|
||||
|
||||
if (maxAccumulatedBalance < Math.abs(balance)) { maxAccumulatedBalance = Math.abs(balance); }
|
||||
|
||||
volumeBars.push(volumeBar);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function calculateAccumulatedBalance(currentDate) {
|
||||
|
||||
let accumulatedBuys = 0;
|
||||
let accumulatedSells = 0;
|
||||
let volumeBar = newAccumulatedVolumeBar();
|
||||
let lastValidBar;
|
||||
let found = false;
|
||||
|
||||
|
||||
|
||||
for (var i = 0; i < marketIndex.volumes.length; i++) {
|
||||
|
||||
let barDate = new Date(marketIndex.volumes[i][3]);
|
||||
|
||||
if (barDate.valueOf() > currentDate.valueOf() && found === false) {
|
||||
lastValidBar = volumeBar; // return the last valid one.
|
||||
found = true;
|
||||
}
|
||||
|
||||
volumeBar = newAccumulatedVolumeBar();
|
||||
let amountBuy = 0;
|
||||
let amountSell = 0;
|
||||
|
||||
volumeBar.begin = (new Date(marketIndex.volumes[i][2])).valueOf();
|
||||
volumeBar.end = (new Date(marketIndex.volumes[i][3])).valueOf();
|
||||
|
||||
amountBuy = marketIndex.volumes[i][0];
|
||||
amountSell = marketIndex.volumes[i][1];
|
||||
|
||||
accumulatedBuys = accumulatedBuys + amountBuy;
|
||||
accumulatedSells = accumulatedSells + amountSell;
|
||||
|
||||
volumeBar.accumulatedBuys = accumulatedBuys;
|
||||
volumeBar.accumulatedSells = accumulatedSells;
|
||||
|
||||
let balance = volumeBar.accumulatedBuys - volumeBar.accumulatedSells;
|
||||
|
||||
if (maxAccumulatedBalance < Math.abs(balance)) { maxAccumulatedBalance = Math.abs(balance); }
|
||||
|
||||
}
|
||||
|
||||
return lastValidBar;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateVolumeBarsUsingDailyFiles(currentDateOnly) {
|
||||
|
||||
let daysOnSides = getSideDays(timePeriod);
|
||||
|
||||
let leftDate;
|
||||
let rightDate;
|
||||
|
||||
if (currentDateOnly === true) {
|
||||
|
||||
leftDate = new Date(datetime.getTime());
|
||||
rightDate = new Date(datetime.getTime());
|
||||
|
||||
leftDate = removeTime(datetime);
|
||||
rightDate = removeTime(datetime);
|
||||
|
||||
} else {
|
||||
|
||||
leftDate = getDateFromPoint(viewPort.visibleArea.topLeft, accumulatedVolumeChartLayer.container, plotArea);
|
||||
rightDate = getDateFromPoint(viewPort.visibleArea.topRight, accumulatedVolumeChartLayer.container, plotArea);
|
||||
|
||||
leftDate.setDate(leftDate.getDate() - daysOnSides);
|
||||
rightDate.setDate(rightDate.getDate() + daysOnSides);
|
||||
|
||||
}
|
||||
|
||||
let currentDate = new Date(leftDate.getTime());
|
||||
|
||||
volumeBars = [];
|
||||
|
||||
let firstFile = true;
|
||||
let accumulatedBuys = 0;
|
||||
let accumulatedSells = 0;
|
||||
maxAccumulatedBalance = 0;
|
||||
|
||||
while (currentDate.getTime() <= rightDate.getTime()) {
|
||||
|
||||
let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2);
|
||||
|
||||
let dailyFile = dailyFilesCursor.dailyFiles.get(stringDate);
|
||||
|
||||
if (dailyFile !== undefined) {
|
||||
|
||||
let lastVolumeBar;
|
||||
|
||||
if (firstFile === true) {
|
||||
|
||||
/* We calculate the initial Accumulated Balance based on the Index Files upto this current date*/
|
||||
|
||||
lastVolumeBar = calculateAccumulatedBalance(currentDate);
|
||||
|
||||
try {
|
||||
|
||||
accumulatedBuys = lastVolumeBar.accumulatedBuys;
|
||||
accumulatedSells = lastVolumeBar.accumulatedSells;
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
// In the situation where there are daily files for a certain date but the index file is not reaching that date, an error is catched here.
|
||||
}
|
||||
|
||||
firstFile = false;
|
||||
}
|
||||
|
||||
const fileTimePeriod = 60 * 1000;
|
||||
const totalVolumeBars = dailyFile.length * fileTimePeriod / timePeriod;
|
||||
const recordsPerVolumeBar = timePeriod / fileTimePeriod;
|
||||
|
||||
for (var i = 0; i < totalVolumeBars; i++) {
|
||||
|
||||
var volumeBar = newAccumulatedVolumeBar();
|
||||
let amountBuy = 0;
|
||||
let amountSell = 0;
|
||||
|
||||
for (var j = 0; j < recordsPerVolumeBar; j++) {
|
||||
|
||||
amountBuy = amountBuy + dailyFile[i * recordsPerVolumeBar + j][8];
|
||||
amountSell = amountSell + dailyFile[i * recordsPerVolumeBar + j][9];
|
||||
|
||||
}
|
||||
|
||||
volumeBar.begin = dailyFile[i * recordsPerVolumeBar][4];
|
||||
volumeBar.end = dailyFile[i * recordsPerVolumeBar + recordsPerVolumeBar - 1][5];
|
||||
|
||||
accumulatedBuys = accumulatedBuys + amountBuy;
|
||||
accumulatedSells = accumulatedSells + amountSell;
|
||||
|
||||
volumeBar.accumulatedBuys = accumulatedBuys;
|
||||
volumeBar.accumulatedSells = accumulatedSells;
|
||||
|
||||
let balance = volumeBar.accumulatedBuys - volumeBar.accumulatedSells;
|
||||
|
||||
|
||||
volumeBars.push(volumeBar);
|
||||
}
|
||||
|
||||
}
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateScaleX() {
|
||||
|
||||
|
||||
var minValue = {
|
||||
x: EARLIEST_DATE.valueOf()
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf()
|
||||
};
|
||||
|
||||
plotArea.initializeX(
|
||||
minValue,
|
||||
maxValue,
|
||||
accumulatedVolumeChartLayer.container.frame.width
|
||||
);
|
||||
|
||||
plotAreaFrame.initializeX(
|
||||
minValue,
|
||||
maxValue,
|
||||
accumulatedVolumeChartLayer.container.frame.width
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateScaleY() {
|
||||
|
||||
var minValue = {
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
y: 0
|
||||
};
|
||||
|
||||
let timePeriodRatio = ONE_DAY_IN_MILISECONDS / timePeriod;
|
||||
|
||||
maxValue.y = marketIndex.maxVolume() / (timePeriodRatio / 10);
|
||||
|
||||
plotArea.initializeY(
|
||||
minValue,
|
||||
maxValue,
|
||||
viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topLeft.y
|
||||
);
|
||||
|
||||
plotAreaFrame.initializeY(
|
||||
minValue,
|
||||
maxValue,
|
||||
accumulatedVolumeChartLayer.container.frame.height
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function plotAccumulatedVolumeBalanceChart() {
|
||||
|
||||
|
||||
|
||||
|
||||
let visibleHeight = viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topLeft.y;
|
||||
|
||||
let frameCorner1 = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
|
||||
let frameCorner2 = {
|
||||
x: accumulatedVolumeChartLayer.container.frame.width,
|
||||
y: accumulatedVolumeChartLayer.container.frame.height
|
||||
};
|
||||
|
||||
|
||||
/* Now the transformations. */
|
||||
|
||||
frameCorner1 = transformThisPoint(frameCorner1, accumulatedVolumeChartLayer.container.frame.container);
|
||||
frameCorner2 = transformThisPoint(frameCorner2, accumulatedVolumeChartLayer.container.frame.container);
|
||||
|
||||
let frameHeightInViewPort = frameCorner2.y - frameCorner1.y;
|
||||
|
||||
if (volumeBars.length > 0) {
|
||||
|
||||
for (var i = 0; i < volumeBars.length; i++) {
|
||||
|
||||
|
||||
volumeBar = volumeBars[i];
|
||||
|
||||
let volumeBarPointA1;
|
||||
let volumeBarPointA2;
|
||||
let volumeBarPointA3;
|
||||
let volumeBarPointA4;
|
||||
|
||||
function calculateBuys(plot, height) {
|
||||
|
||||
volumeBarPointA1 = {
|
||||
x: volumeBar.begin,
|
||||
y: 0
|
||||
};
|
||||
|
||||
volumeBarPointA2 = {
|
||||
x: volumeBar.begin,
|
||||
y: 0
|
||||
};
|
||||
|
||||
volumeBarPointA3 = {
|
||||
x: volumeBar.end,
|
||||
y: 0
|
||||
};
|
||||
|
||||
volumeBarPointA4 = {
|
||||
x: volumeBar.end,
|
||||
y: 0
|
||||
};
|
||||
|
||||
volumeBarPointA1 = plot.inverseTransform(volumeBarPointA1, height);
|
||||
volumeBarPointA2 = plot.inverseTransform(volumeBarPointA2, height);
|
||||
volumeBarPointA3 = plot.inverseTransform(volumeBarPointA3, height);
|
||||
volumeBarPointA4 = plot.inverseTransform(volumeBarPointA4, height);
|
||||
|
||||
volumeBarPointA1 = transformThisPoint(volumeBarPointA1, accumulatedVolumeChartLayer.container);
|
||||
volumeBarPointA2 = transformThisPoint(volumeBarPointA2, accumulatedVolumeChartLayer.container);
|
||||
volumeBarPointA3 = transformThisPoint(volumeBarPointA3, accumulatedVolumeChartLayer.container);
|
||||
volumeBarPointA4 = transformThisPoint(volumeBarPointA4, accumulatedVolumeChartLayer.container);
|
||||
|
||||
if (volumeBarPointA4.x < viewPort.visibleArea.bottomLeft.x || volumeBarPointA1.x > viewPort.visibleArea.bottomRight.x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
if (calculateBuys(plotAreaFrame, accumulatedVolumeChartLayer.container.frame.height) === false) { continue; } // We try to see if it fits in the visible area.
|
||||
|
||||
let volumeBarPointB1;
|
||||
let volumeBarPointB2;
|
||||
let volumeBarPointB3;
|
||||
let volumeBarPointB4;
|
||||
|
||||
function calculateSells(plot, height) {
|
||||
|
||||
volumeBarPointB1 = {
|
||||
x: volumeBar.begin,
|
||||
y: height
|
||||
};
|
||||
|
||||
volumeBarPointB2 = {
|
||||
x: volumeBar.begin,
|
||||
y: height - volumeBar.amountSell
|
||||
};
|
||||
|
||||
volumeBarPointB3 = {
|
||||
x: volumeBar.end,
|
||||
y: height - volumeBar.amountSell
|
||||
};
|
||||
|
||||
volumeBarPointB4 = {
|
||||
x: volumeBar.end,
|
||||
y: height
|
||||
};
|
||||
|
||||
volumeBarPointB1 = plot.inverseTransform2(volumeBarPointB1, height);
|
||||
volumeBarPointB2 = plot.inverseTransform2(volumeBarPointB2, height);
|
||||
volumeBarPointB3 = plot.inverseTransform2(volumeBarPointB3, height);
|
||||
volumeBarPointB4 = plot.inverseTransform2(volumeBarPointB4, height);
|
||||
|
||||
volumeBarPointB1 = transformThisPoint(volumeBarPointB1, accumulatedVolumeChartLayer.container);
|
||||
volumeBarPointB2 = transformThisPoint(volumeBarPointB2, accumulatedVolumeChartLayer.container);
|
||||
volumeBarPointB3 = transformThisPoint(volumeBarPointB3, accumulatedVolumeChartLayer.container);
|
||||
volumeBarPointB4 = transformThisPoint(volumeBarPointB4, accumulatedVolumeChartLayer.container);
|
||||
|
||||
}
|
||||
|
||||
calculateSells(plotAreaFrame, accumulatedVolumeChartLayer.container.frame.height); // We try to see if it fits in the visible area.
|
||||
|
||||
if (volumeBarPointB1.y < viewPort.visibleArea.topLeft.y && frameHeightInViewPort > visibleHeight * 2 / 3) {
|
||||
|
||||
calculateSells(plotArea, visibleHeight); // We snap it to the view port.
|
||||
|
||||
/* Now we set the real value of y. */
|
||||
|
||||
volumeBarPointB1.y = viewPort.visibleArea.topLeft.y;
|
||||
volumeBarPointB2.y = viewPort.visibleArea.topLeft.y + volumeBar.amountSell * plotArea.scale.y;
|
||||
volumeBarPointB3.y = viewPort.visibleArea.topLeft.y + volumeBar.amountSell * plotArea.scale.y;
|
||||
volumeBarPointB4.y = viewPort.visibleArea.topLeft.y;
|
||||
|
||||
}
|
||||
|
||||
/* Everything must fit within the visible area */
|
||||
|
||||
volumeBarPointA1 = viewPort.fitIntoVisibleArea(volumeBarPointA1);
|
||||
volumeBarPointA2 = viewPort.fitIntoVisibleArea(volumeBarPointA2);
|
||||
volumeBarPointA3 = viewPort.fitIntoVisibleArea(volumeBarPointA3);
|
||||
volumeBarPointA4 = viewPort.fitIntoVisibleArea(volumeBarPointA4);
|
||||
|
||||
volumeBarPointB1 = viewPort.fitIntoVisibleArea(volumeBarPointB1);
|
||||
volumeBarPointB2 = viewPort.fitIntoVisibleArea(volumeBarPointB2);
|
||||
volumeBarPointB3 = viewPort.fitIntoVisibleArea(volumeBarPointB3);
|
||||
volumeBarPointB4 = viewPort.fitIntoVisibleArea(volumeBarPointB4);
|
||||
|
||||
/* 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 (volumeBarPointA2.y < volumeBarPointB1.y) {
|
||||
|
||||
volumeBarPointA2.y = volumeBarPointB1.y;
|
||||
volumeBarPointA3.y = volumeBarPointB1.y;
|
||||
|
||||
}
|
||||
|
||||
if (volumeBarPointB2.y > volumeBarPointA1.y) {
|
||||
|
||||
volumeBarPointB2.y = volumeBarPointA1.y;
|
||||
volumeBarPointB3.y = volumeBarPointA1.y;
|
||||
|
||||
}
|
||||
|
||||
/* Here we will plot the balance of accumulated buys and sells */
|
||||
|
||||
let balance = volumeBar.accumulatedBuys - volumeBar.accumulatedSells;
|
||||
let heigh = MAX_ACCUMULATED_BALANCE_BARS_HEIGHT;
|
||||
let scale = MAX_ACCUMULATED_BALANCE_BARS_HEIGHT / maxAccumulatedBalance;
|
||||
const OPACITY = '0.15';
|
||||
|
||||
if (balance > 0) {
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(volumeBarPointA1.x, PLOT_Y_BASE_LINE);
|
||||
browserCanvasContext.lineTo(volumeBarPointA2.x, PLOT_Y_BASE_LINE - balance * scale);
|
||||
browserCanvasContext.lineTo(volumeBarPointA3.x, PLOT_Y_BASE_LINE - balance * scale);
|
||||
browserCanvasContext.lineTo(volumeBarPointA4.x, PLOT_Y_BASE_LINE);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= volumeBar.begin && dateValue <= volumeBar.end) {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, ' + OPACITY + ')'; // Current bar accroding to time
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(64, 217, 26, ' + OPACITY + ')';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(64, 217, 26, ' + OPACITY + ')';
|
||||
|
||||
}
|
||||
|
||||
browserCanvasContext.fill();
|
||||
browserCanvasContext.strokeStyle = 'rgba(27, 105, 7, ' + OPACITY + ')';
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(volumeBarPointB2.x, PLOT_Y_BASE_LINE);
|
||||
browserCanvasContext.lineTo(volumeBarPointB3.x, PLOT_Y_BASE_LINE);
|
||||
browserCanvasContext.lineTo(volumeBarPointB3.x, PLOT_Y_BASE_LINE - balance * scale);
|
||||
browserCanvasContext.lineTo(volumeBarPointB2.x, PLOT_Y_BASE_LINE - balance * scale);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= volumeBar.begin && dateValue <= volumeBar.end) {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, ' + OPACITY + ')'; // Current bar accroding to time
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(219, 18, 18, ' + OPACITY + ')';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(219, 18, 18, ' + OPACITY + ')';
|
||||
|
||||
}
|
||||
|
||||
browserCanvasContext.fill();
|
||||
browserCanvasContext.strokeStyle = 'rgba(130, 9, 9, ' + OPACITY + ')';
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,382 +0,0 @@
|
||||
|
||||
function newAllTimeChartLayer() {
|
||||
|
||||
|
||||
let timePeriod = INITIAL_TIME_PERIOD;
|
||||
|
||||
var plotArea = newPlotArea();
|
||||
var plotAreaFrame = newPlotArea();
|
||||
|
||||
let datetime = INITIAL_DATE;
|
||||
|
||||
var allTimeChartLayer = {
|
||||
onLayerStatusChanged: onLayerStatusChanged,
|
||||
setTimePeriod: setTimePeriod,
|
||||
setDatetime: setDatetime,
|
||||
container: undefined,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
var container = newContainer();
|
||||
container.initialize();
|
||||
allTimeChartLayer.container = container;
|
||||
|
||||
container.displacement.containerName = "All Time Chart";
|
||||
container.zoom.containerName = "All Time Chart";
|
||||
container.frame.containerName = "All Time Chart";
|
||||
|
||||
|
||||
|
||||
var marketId;
|
||||
var exchangeId;
|
||||
|
||||
let marketIndex;
|
||||
|
||||
let allTimeHigh;
|
||||
let allTimeLow;
|
||||
|
||||
let allTimeHighs = [];
|
||||
let allTimeLows = [];
|
||||
|
||||
let layerStatus = 'off';
|
||||
|
||||
return allTimeChartLayer;
|
||||
|
||||
function initialize(exchange, market, index, botsPanel) {
|
||||
|
||||
marketId = market;
|
||||
exchangeId = exchange;
|
||||
|
||||
marketIndex = index;
|
||||
|
||||
recalculateScale();
|
||||
|
||||
let server = newFileServer();
|
||||
server.initialize();
|
||||
|
||||
server.getAllTimes(exchangeId, marketId, onFileReady);
|
||||
|
||||
function onFileReady(file) {
|
||||
|
||||
allTimes = file;
|
||||
|
||||
for (let i = 0; i < allTimes.length; i++) {
|
||||
|
||||
if (allTimes[i][0] === 'high') {
|
||||
allTimeHighs.push([allTimes[i][1], allTimes[i][2]]);
|
||||
}
|
||||
|
||||
if (allTimes[i][0] === 'low') {
|
||||
allTimeLows.push([allTimes[i][1], allTimes[i][2]]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
layerStatus = botsPanel.getProductStatus(botsPanel.layerNames.ATH);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getContainer(point) {
|
||||
|
||||
var container;
|
||||
|
||||
/* First we check if this point is inside this space. */
|
||||
|
||||
if (this.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return this.container;
|
||||
|
||||
} else {
|
||||
|
||||
/* This point does not belong to this space. */
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onLayerStatusChanged(eventData) {
|
||||
|
||||
if (eventData.layer === 'All-time Highs and Lows') {
|
||||
layerStatus = eventData.status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function setTimePeriod(period) {
|
||||
|
||||
timePeriod = period;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setDatetime(newDatetime) {
|
||||
datetime = newDatetime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
if (layerStatus !== 'on') { return; }
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
plotAllTimeChart();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function recalculateScale() {
|
||||
|
||||
var minValue = {
|
||||
x: EARLIEST_DATE.valueOf(),
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf(),
|
||||
y: nextPorwerOf10(marketIndex.maxRate())
|
||||
};
|
||||
|
||||
|
||||
plotArea.initialize(
|
||||
minValue,
|
||||
maxValue,
|
||||
allTimeChartLayer.container.frame.width,
|
||||
allTimeChartLayer.container.frame.height
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function plotAllTimeChart() {
|
||||
|
||||
|
||||
let firstHighRate = 0;
|
||||
let firstLowRate = 0;
|
||||
|
||||
if (marketIndex.candles.length > 0) {
|
||||
|
||||
firstHighRate = marketIndex.candles[0][2];
|
||||
firstLowRate = marketIndex.candles[0][2];
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (allTimeHighs.length > 0) {
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
let leftCornerPoint = {
|
||||
x: plotArea.min.x,
|
||||
y: plotArea.max.y
|
||||
};
|
||||
|
||||
leftCornerPoint = plotArea.inverseTransform(leftCornerPoint, allTimeChartLayer.container.frame.height);
|
||||
leftCornerPoint = transformThisPoint(leftCornerPoint, allTimeChartLayer.container);
|
||||
leftCornerPoint = viewPort.fitIntoVisibleArea(leftCornerPoint);
|
||||
|
||||
browserCanvasContext.moveTo(leftCornerPoint.x, leftCornerPoint.y);
|
||||
|
||||
let firstPoint = {
|
||||
x: plotArea.min.x,
|
||||
y: firstHighRate
|
||||
};
|
||||
|
||||
firstPoint = plotArea.inverseTransform(firstPoint, allTimeChartLayer.container.frame.height);
|
||||
firstPoint = transformThisPoint(firstPoint, allTimeChartLayer.container);
|
||||
firstPoint = viewPort.fitIntoVisibleArea(firstPoint);
|
||||
|
||||
browserCanvasContext.lineTo(firstPoint.x, firstPoint.y);
|
||||
|
||||
let lastRate = firstHighRate;
|
||||
|
||||
for (var i = 0; i < allTimeHighs.length; i++) {
|
||||
|
||||
let rate = allTimeHighs[i][0];
|
||||
let begin = Math.trunc(allTimeHighs[i][1] / timePeriod) * timePeriod + timePeriod / 2;
|
||||
|
||||
let allTimePointA;
|
||||
|
||||
allTimePointA = {
|
||||
x: begin,
|
||||
y: lastRate
|
||||
};
|
||||
|
||||
allTimePointA = plotArea.inverseTransform(allTimePointA, allTimeChartLayer.container.frame.height);
|
||||
allTimePointA = transformThisPoint(allTimePointA, allTimeChartLayer.container);
|
||||
allTimePointA = viewPort.fitIntoVisibleArea(allTimePointA);
|
||||
|
||||
browserCanvasContext.lineTo(allTimePointA.x, allTimePointA.y);
|
||||
|
||||
let allTimePointB;
|
||||
|
||||
allTimePointB = {
|
||||
x: begin,
|
||||
y: rate
|
||||
};
|
||||
|
||||
allTimePointB = plotArea.inverseTransform(allTimePointB, allTimeChartLayer.container.frame.height);
|
||||
allTimePointB = transformThisPoint(allTimePointB, allTimeChartLayer.container);
|
||||
allTimePointB = viewPort.fitIntoVisibleArea(allTimePointB);
|
||||
|
||||
browserCanvasContext.lineTo(allTimePointB.x, allTimePointB.y);
|
||||
|
||||
lastRate = rate;
|
||||
}
|
||||
|
||||
let lastPoint = {
|
||||
x: plotArea.max.x,
|
||||
y: allTimeHighs[allTimeHighs.length - 1][0]
|
||||
};
|
||||
|
||||
lastPoint = plotArea.inverseTransform(lastPoint, allTimeChartLayer.container.frame.height);
|
||||
lastPoint = transformThisPoint(lastPoint, allTimeChartLayer.container);
|
||||
lastPoint = viewPort.fitIntoVisibleArea(lastPoint);
|
||||
|
||||
browserCanvasContext.lineTo(lastPoint.x, lastPoint.y);
|
||||
|
||||
let rightCornerPoint = {
|
||||
x: plotArea.max.x,
|
||||
y: plotArea.max.y
|
||||
};
|
||||
|
||||
rightCornerPoint = plotArea.inverseTransform(rightCornerPoint, allTimeChartLayer.container.frame.height);
|
||||
rightCornerPoint = transformThisPoint(rightCornerPoint, allTimeChartLayer.container);
|
||||
rightCornerPoint = viewPort.fitIntoVisibleArea(rightCornerPoint);
|
||||
|
||||
browserCanvasContext.lineTo(rightCornerPoint.x, rightCornerPoint.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
const OPACITY = '0.05';
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(0, 229, 255, ' + OPACITY + ')';
|
||||
|
||||
browserCanvasContext.fill();
|
||||
browserCanvasContext.strokeStyle = 'rgba(0, 140, 255, ' + OPACITY + ')';
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (allTimeLows.length > 0) {
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
let leftCornerPoint = {
|
||||
x: plotArea.min.x,
|
||||
y: plotArea.min.y
|
||||
};
|
||||
|
||||
leftCornerPoint = plotArea.inverseTransform(leftCornerPoint, allTimeChartLayer.container.frame.height);
|
||||
leftCornerPoint = transformThisPoint(leftCornerPoint, allTimeChartLayer.container);
|
||||
leftCornerPoint = viewPort.fitIntoVisibleArea(leftCornerPoint);
|
||||
|
||||
browserCanvasContext.moveTo(leftCornerPoint.x, leftCornerPoint.y);
|
||||
|
||||
let firstPoint = {
|
||||
x: plotArea.min.x,
|
||||
y: firstLowRate
|
||||
};
|
||||
|
||||
firstPoint = plotArea.inverseTransform(firstPoint, allTimeChartLayer.container.frame.height);
|
||||
firstPoint = transformThisPoint(firstPoint, allTimeChartLayer.container);
|
||||
firstPoint = viewPort.fitIntoVisibleArea(firstPoint);
|
||||
|
||||
browserCanvasContext.lineTo(firstPoint.x, firstPoint.y);
|
||||
|
||||
let lastRate = firstLowRate;
|
||||
|
||||
for (var i = 0; i < allTimeLows.length; i++) {
|
||||
|
||||
let rate = allTimeLows[i][0];
|
||||
let begin = Math.trunc(allTimeLows[i][1] / timePeriod) * timePeriod + timePeriod / 2;
|
||||
|
||||
let allTimePointA;
|
||||
|
||||
allTimePointA = {
|
||||
x: begin,
|
||||
y: lastRate
|
||||
};
|
||||
|
||||
allTimePointA = plotArea.inverseTransform(allTimePointA, allTimeChartLayer.container.frame.height);
|
||||
allTimePointA = transformThisPoint(allTimePointA, allTimeChartLayer.container);
|
||||
allTimePointA = viewPort.fitIntoVisibleArea(allTimePointA);
|
||||
|
||||
browserCanvasContext.lineTo(allTimePointA.x, allTimePointA.y);
|
||||
|
||||
let allTimePointB;
|
||||
|
||||
allTimePointB = {
|
||||
x: begin,
|
||||
y: rate
|
||||
};
|
||||
|
||||
allTimePointB = plotArea.inverseTransform(allTimePointB, allTimeChartLayer.container.frame.height);
|
||||
allTimePointB = transformThisPoint(allTimePointB, allTimeChartLayer.container);
|
||||
allTimePointB = viewPort.fitIntoVisibleArea(allTimePointB);
|
||||
|
||||
browserCanvasContext.lineTo(allTimePointB.x, allTimePointB.y);
|
||||
|
||||
lastRate = rate;
|
||||
}
|
||||
|
||||
let lastPoint = {
|
||||
x: plotArea.max.x,
|
||||
y: allTimeLows[allTimeLows.length - 1][0]
|
||||
};
|
||||
|
||||
lastPoint = plotArea.inverseTransform(lastPoint, allTimeChartLayer.container.frame.height);
|
||||
lastPoint = transformThisPoint(lastPoint, allTimeChartLayer.container);
|
||||
lastPoint = viewPort.fitIntoVisibleArea(lastPoint);
|
||||
|
||||
browserCanvasContext.lineTo(lastPoint.x, lastPoint.y);
|
||||
|
||||
let rightCornerPoint = {
|
||||
x: plotArea.max.x,
|
||||
y: plotArea.min.y
|
||||
};
|
||||
|
||||
rightCornerPoint = plotArea.inverseTransform(rightCornerPoint, allTimeChartLayer.container.frame.height);
|
||||
rightCornerPoint = transformThisPoint(rightCornerPoint, allTimeChartLayer.container);
|
||||
rightCornerPoint = viewPort.fitIntoVisibleArea(rightCornerPoint);
|
||||
|
||||
browserCanvasContext.lineTo(rightCornerPoint.x, rightCornerPoint.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
const OPACITY = '0.05';
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(168, 77, 2, ' + OPACITY + ')';
|
||||
|
||||
browserCanvasContext.fill();
|
||||
browserCanvasContext.strokeStyle = 'rgba(255, 115, 0, ' + OPACITY + ')';
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,601 +0,0 @@
|
||||
|
||||
function newCandleStickChartLayer() {
|
||||
|
||||
|
||||
var candles = [];
|
||||
let timePeriod = INITIAL_TIME_PERIOD;
|
||||
|
||||
var plotArea = newPlotArea();
|
||||
|
||||
var datetime = INITIAL_DATE;
|
||||
|
||||
var candleStickChartLayer = {
|
||||
onLayerStatusChanged: onLayerStatusChanged,
|
||||
currentCandle: undefined,
|
||||
positionAtDatetime: positionAtDatetime,
|
||||
setTimePeriod: setTimePeriod,
|
||||
setDatetime: setDatetime,
|
||||
container: undefined,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
var container = newContainer();
|
||||
container.initialize();
|
||||
candleStickChartLayer.container = container;
|
||||
|
||||
container.displacement.containerName = "Candle Stick Chart";
|
||||
container.zoom.containerName = "Candle Stick Chart";
|
||||
container.frame.containerName = "Candle Stick Chart";
|
||||
|
||||
let marketId;
|
||||
let exchangeId;
|
||||
|
||||
let marketIndex;
|
||||
let dailyFilesCursor;
|
||||
|
||||
let layerStatus = 'off';
|
||||
|
||||
return candleStickChartLayer;
|
||||
|
||||
function initialize(exchange, market, index, dailyFiles, botsPanel) {
|
||||
|
||||
marketId = market;
|
||||
exchangeId = exchange;
|
||||
|
||||
marketIndex = index;
|
||||
dailyFilesCursor = dailyFiles;
|
||||
|
||||
recalculateScale();
|
||||
recalculateCandlesUsingDailyFiles(true); // We need the first day of candles so as to see which is going to be the center of the viewport.
|
||||
|
||||
if (marketId === INITIAL_DEFAULT_MARKET) { // For now, lets position the view port at the market USDT/BTC
|
||||
|
||||
postitionViewPort();
|
||||
|
||||
}
|
||||
|
||||
recalculateCandles();
|
||||
|
||||
viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged);
|
||||
canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished);
|
||||
|
||||
layerStatus = botsPanel.getProductStatus(botsPanel.layerNames.CANDLESTICKS);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getContainer(point) {
|
||||
|
||||
if (layerStatus !== 'on') { return; }
|
||||
|
||||
var container;
|
||||
|
||||
/* First we check if this point is inside this space. */
|
||||
|
||||
if (this.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return this.container;
|
||||
|
||||
} else {
|
||||
|
||||
/* This point does not belong to this space. */
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onLayerStatusChanged(eventData) {
|
||||
|
||||
if (eventData.layer === 'Candlesticks') {
|
||||
layerStatus = eventData.status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onZoomChanged(event) {
|
||||
|
||||
recalculateCandles();
|
||||
|
||||
}
|
||||
|
||||
function onDragFinished() {
|
||||
|
||||
if (timePeriod !== ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
recalculateCandles();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function setTimePeriod(period) {
|
||||
|
||||
timePeriod = period;
|
||||
|
||||
}
|
||||
|
||||
function setDatetime(newDatetime) {
|
||||
|
||||
datetime = newDatetime;
|
||||
recalculateCandles();
|
||||
}
|
||||
|
||||
|
||||
function postitionViewPort() {
|
||||
|
||||
try {
|
||||
|
||||
let targetPoint = {
|
||||
x: candles[Math.round(candles.length / 2)].begin,
|
||||
y: candles[Math.round(candles.length / 2)].min + (candles[Math.round(candles.length / 2)].max - candles[Math.round(candles.length / 2)].min)
|
||||
};
|
||||
|
||||
targetPoint = plotArea.inverseTransform(targetPoint, candleStickChartLayer.container.frame.height);
|
||||
targetPoint = transformThisPoint(targetPoint, candleStickChartLayer.container);
|
||||
|
||||
let displaceVector = {
|
||||
x: (viewPort.visibleArea.bottomRight.x - viewPort.visibleArea.topLeft.x) / 2 - targetPoint.x,
|
||||
y: (viewPort.visibleArea.bottomLeft.y - viewPort.visibleArea.topLeft.y) / 2 - targetPoint.y
|
||||
};
|
||||
|
||||
viewPort.displace(displaceVector);
|
||||
|
||||
} catch (err) {
|
||||
|
||||
// if there data is missing of the days it must position in then an exception is raised.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function positionAtDatetime(newDatetime) {
|
||||
|
||||
value = newDatetime.valueOf();
|
||||
|
||||
/* Now we calculate which candle has this new time, because it will give us the y coordinate. */
|
||||
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
|
||||
if (value >= candles[i].begin && value <= candles[i].end) {
|
||||
|
||||
let targetPoint = {
|
||||
x: value,
|
||||
y: candles[i].open
|
||||
};
|
||||
|
||||
targetPoint = plotArea.inverseTransform(targetPoint, candleStickChartLayer.container.frame.height);
|
||||
targetPoint = transformThisPoint(targetPoint, candleStickChartLayer.container);
|
||||
|
||||
let targetMax = {
|
||||
x: value,
|
||||
y: candles[i].max
|
||||
};
|
||||
|
||||
targetMax = plotArea.inverseTransform(targetMax, candleStickChartLayer.container.frame.height);
|
||||
targetMax = transformThisPoint(targetMax, candleStickChartLayer.container);
|
||||
|
||||
let targetMin = {
|
||||
x: value,
|
||||
y: candles[i].min
|
||||
};
|
||||
|
||||
targetMin = plotArea.inverseTransform(targetMin, candleStickChartLayer.container.frame.height);
|
||||
targetMin = transformThisPoint(targetMin, candleStickChartLayer.container);
|
||||
|
||||
let center = {
|
||||
x: (viewPort.visibleArea.bottomRight.x - viewPort.visibleArea.bottomLeft.x) / 2,
|
||||
y: (viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topRight.y) / 2
|
||||
};
|
||||
|
||||
if (targetMax.y < viewPort.visibleArea.topLeft.y || targetMin.y > viewPort.visibleArea.bottomRight.y) {
|
||||
|
||||
let displaceVector = {
|
||||
x: 0,
|
||||
y: center.y - targetPoint.y
|
||||
};
|
||||
|
||||
viewPort.displaceTarget(displaceVector);
|
||||
|
||||
}
|
||||
|
||||
let displaceVector = {
|
||||
x: center.x - targetPoint.x,
|
||||
y: 0
|
||||
};
|
||||
|
||||
viewPort.displace(displaceVector);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
if (layerStatus !== 'on') { return; }
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
if (timePeriod !== ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
if (Math.random() * 100 > 98) {
|
||||
recalculateCandles();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
plotCandleChart();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function recalculateCandles() {
|
||||
|
||||
if (layerStatus === 'off') { return; }
|
||||
|
||||
if (timePeriod === ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
recalculateCandlesUsingMarketIndex();
|
||||
|
||||
} else {
|
||||
|
||||
recalculateCandlesUsingDailyFiles();
|
||||
|
||||
}
|
||||
|
||||
candleStickChartLayer.container.eventHandler.raiseEvent("Candles Changed", candles);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function recalculateCandlesUsingDailyFiles(currentDateOnly) {
|
||||
|
||||
let daysOnSides = getSideDays(timePeriod);
|
||||
|
||||
let leftDate;
|
||||
let rightDate;
|
||||
|
||||
if (currentDateOnly === true) {
|
||||
|
||||
leftDate = new Date(datetime.getTime());
|
||||
rightDate = new Date(datetime.getTime());
|
||||
|
||||
leftDate = removeTime(datetime);
|
||||
rightDate = removeTime(datetime);
|
||||
|
||||
} else {
|
||||
|
||||
leftDate = getDateFromPoint(viewPort.visibleArea.topLeft, candleStickChartLayer.container, plotArea);
|
||||
rightDate = getDateFromPoint(viewPort.visibleArea.topRight, candleStickChartLayer.container, plotArea);
|
||||
|
||||
|
||||
|
||||
leftDate.setDate(leftDate.getDate() - daysOnSides);
|
||||
rightDate.setDate(rightDate.getDate() + daysOnSides);
|
||||
|
||||
}
|
||||
|
||||
let currentDate = new Date(leftDate.getTime());
|
||||
|
||||
candles = [];
|
||||
|
||||
while (currentDate.getTime() <= rightDate.getTime()) {
|
||||
|
||||
let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2);
|
||||
|
||||
let dailyFile = dailyFilesCursor.dailyFiles.get(stringDate);
|
||||
|
||||
if (dailyFile !== undefined) {
|
||||
|
||||
const fileTimePeriod = 60 * 1000;
|
||||
const totalCandles = dailyFile.length * fileTimePeriod / timePeriod;
|
||||
const recordsPerCandle = timePeriod / fileTimePeriod;
|
||||
|
||||
for (var i = 0; i < totalCandles; i++) {
|
||||
|
||||
var candle = newCandle();
|
||||
|
||||
let min = dailyFile[i * recordsPerCandle][0];
|
||||
let max = dailyFile[i * recordsPerCandle][1];
|
||||
|
||||
for (var j = 0; j < recordsPerCandle; j++) {
|
||||
|
||||
if (dailyFile[i * recordsPerCandle + j][0] < min) {
|
||||
|
||||
min = dailyFile[i * recordsPerCandle + j][0];
|
||||
}
|
||||
|
||||
if (dailyFile[i * recordsPerCandle + j][1] > max) {
|
||||
|
||||
max = dailyFile[i * recordsPerCandle + j][1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
candle.min = min;
|
||||
candle.max = max;
|
||||
|
||||
candle.open = dailyFile[i * recordsPerCandle][2];
|
||||
candle.close = dailyFile[i * recordsPerCandle + recordsPerCandle - 1][3];
|
||||
|
||||
candle.begin = dailyFile[i * recordsPerCandle][4];
|
||||
candle.end = dailyFile[i * recordsPerCandle + recordsPerCandle - 1][5];
|
||||
|
||||
candle.beginId = dailyFile[i * recordsPerCandle][6];
|
||||
candle.endId = dailyFile[i * recordsPerCandle + recordsPerCandle - 1][7];
|
||||
|
||||
if (candle.open > candle.close) { candle.direction = 'down'; }
|
||||
if (candle.open < candle.close) { candle.direction = 'up'; }
|
||||
if (candle.open === candle.close) { candle.direction = 'side'; }
|
||||
|
||||
candles.push(candle);
|
||||
|
||||
if (datetime.valueOf() >= candle.begin && datetime.valueOf() <= candle.end) {
|
||||
|
||||
candleStickChartLayer.currentCandle = candle;
|
||||
candleStickChartLayer.container.eventHandler.raiseEvent("Current Candle Changed", candleStickChartLayer.currentCandle);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateCandlesUsingMarketIndex() {
|
||||
|
||||
candles = [];
|
||||
|
||||
for (var i = 0; i < marketIndex.candles.length; i++) {
|
||||
|
||||
var candle = newCandle();
|
||||
|
||||
candle.min = marketIndex.candles[i][0];
|
||||
candle.max = marketIndex.candles[i][1];
|
||||
|
||||
candle.open = marketIndex.candles[i][2];
|
||||
candle.close = marketIndex.candles[i][3];
|
||||
|
||||
candle.begin = (new Date(marketIndex.candles[i][4])).valueOf();
|
||||
candle.end = (new Date(marketIndex.candles[i][5])).valueOf();
|
||||
|
||||
candle.beginId = marketIndex.candles[i][6];
|
||||
candle.endId = marketIndex.candles[i][7];
|
||||
|
||||
if (candle.open > candle.close) { candle.direction = 'down'; }
|
||||
if (candle.open < candle.close) { candle.direction = 'up'; }
|
||||
if (candle.open === candle.close) { candle.direction = 'side'; }
|
||||
|
||||
candles.push(candle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function recalculateScale() {
|
||||
|
||||
var minValue = {
|
||||
x: EARLIEST_DATE.valueOf(),
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf(),
|
||||
y: nextPorwerOf10(marketIndex.maxRate())
|
||||
};
|
||||
|
||||
|
||||
plotArea.initialize(
|
||||
minValue,
|
||||
maxValue,
|
||||
candleStickChartLayer.container.frame.width,
|
||||
candleStickChartLayer.container.frame.height
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function plotCandleChart() {
|
||||
|
||||
if (candles.length > 0) {
|
||||
|
||||
/* Now we calculate and plot the candles */
|
||||
|
||||
for (var i = 0; i < candles.length; i++) {
|
||||
|
||||
candle = candles[i];
|
||||
|
||||
var candlePoint1 = {
|
||||
x: candle.begin + timePeriod / 7 * 1.5,
|
||||
y: candle.open
|
||||
};
|
||||
|
||||
var candlePoint2 = {
|
||||
x: candle.begin + timePeriod / 7 * 5.5,
|
||||
y: candle.open
|
||||
};
|
||||
|
||||
var candlePoint3 = {
|
||||
x: candle.begin + timePeriod / 7 * 5.5,
|
||||
y: candle.close
|
||||
};
|
||||
|
||||
var candlePoint4 = {
|
||||
x: candle.begin + timePeriod / 7 * 1.5,
|
||||
y: candle.close
|
||||
};
|
||||
|
||||
candlePoint1 = plotArea.inverseTransform(candlePoint1, candleStickChartLayer.container.frame.height);
|
||||
candlePoint2 = plotArea.inverseTransform(candlePoint2, candleStickChartLayer.container.frame.height);
|
||||
candlePoint3 = plotArea.inverseTransform(candlePoint3, candleStickChartLayer.container.frame.height);
|
||||
candlePoint4 = plotArea.inverseTransform(candlePoint4, candleStickChartLayer.container.frame.height);
|
||||
|
||||
candlePoint1 = transformThisPoint(candlePoint1, candleStickChartLayer.container);
|
||||
candlePoint2 = transformThisPoint(candlePoint2, candleStickChartLayer.container);
|
||||
candlePoint3 = transformThisPoint(candlePoint3, candleStickChartLayer.container);
|
||||
candlePoint4 = transformThisPoint(candlePoint4, candleStickChartLayer.container);
|
||||
|
||||
if (candlePoint2.x < viewPort.visibleArea.bottomLeft.x || candlePoint1.x > viewPort.visibleArea.bottomRight.x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
candlePoint1 = viewPort.fitIntoVisibleArea(candlePoint1);
|
||||
candlePoint2 = viewPort.fitIntoVisibleArea(candlePoint2);
|
||||
candlePoint3 = viewPort.fitIntoVisibleArea(candlePoint3);
|
||||
candlePoint4 = viewPort.fitIntoVisibleArea(candlePoint4);
|
||||
|
||||
var stickPoint1 = {
|
||||
x: candle.begin + timePeriod / 7 * 3.2,
|
||||
y: candle.max
|
||||
};
|
||||
|
||||
var stickPoint2 = {
|
||||
x: candle.begin + timePeriod / 7 * 3.8,
|
||||
y: candle.max
|
||||
};
|
||||
|
||||
var stickPoint3 = {
|
||||
x: candle.begin + timePeriod / 7 * 3.8,
|
||||
y: candle.min
|
||||
};
|
||||
|
||||
var stickPoint4 = {
|
||||
x: candle.begin + timePeriod / 7 * 3.2,
|
||||
y: candle.min
|
||||
};
|
||||
|
||||
stickPoint1 = plotArea.inverseTransform(stickPoint1, candleStickChartLayer.container.frame.height);
|
||||
stickPoint2 = plotArea.inverseTransform(stickPoint2, candleStickChartLayer.container.frame.height);
|
||||
stickPoint3 = plotArea.inverseTransform(stickPoint3, candleStickChartLayer.container.frame.height);
|
||||
stickPoint4 = plotArea.inverseTransform(stickPoint4, candleStickChartLayer.container.frame.height);
|
||||
|
||||
stickPoint1 = transformThisPoint(stickPoint1, candleStickChartLayer.container);
|
||||
stickPoint2 = transformThisPoint(stickPoint2, candleStickChartLayer.container);
|
||||
stickPoint3 = transformThisPoint(stickPoint3, candleStickChartLayer.container);
|
||||
stickPoint4 = transformThisPoint(stickPoint4, candleStickChartLayer.container);
|
||||
|
||||
stickPoint1 = viewPort.fitIntoVisibleArea(stickPoint1);
|
||||
stickPoint2 = viewPort.fitIntoVisibleArea(stickPoint2);
|
||||
stickPoint3 = viewPort.fitIntoVisibleArea(stickPoint3);
|
||||
stickPoint4 = viewPort.fitIntoVisibleArea(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(54, 54, 54, 1)';
|
||||
browserCanvasContext.fill();
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= candle.begin && dateValue <= candle.end) {
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(255, 233, 31, 1)'; // Current candle accroding to time
|
||||
|
||||
} else {
|
||||
browserCanvasContext.strokeStyle = 'rgba(212, 206, 201, 1)';
|
||||
}
|
||||
|
||||
} else {
|
||||
browserCanvasContext.strokeStyle = 'rgba(212, 206, 201, 1)';
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (candle.direction === 'up') { browserCanvasContext.strokeStyle = 'rgba(27, 105, 7, 1)'; }
|
||||
if (candle.direction === 'down') { browserCanvasContext.strokeStyle = 'rgba(130, 9, 9, 1)'; }
|
||||
if (candle.direction === 'side') { browserCanvasContext.strokeStyle = 'rgba(27, 7, 105, 1)'; }
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= candle.begin && dateValue <= candle.end) {
|
||||
|
||||
/* highlight the current candle */
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, 1)'; // Current candle accroding to time
|
||||
|
||||
let currentCandle = {
|
||||
bodyWidth: candlePoint2.x - candlePoint1.x,
|
||||
bodyHeight: candlePoint3.y - candlePoint2.y,
|
||||
stickHeight: stickPoint4.y - stickPoint2.y,
|
||||
stickWidth: stickPoint2.x - stickPoint1.x,
|
||||
stickStart: candlePoint2.y - stickPoint2.y,
|
||||
period: timePeriod,
|
||||
innerCandle: candle
|
||||
};
|
||||
|
||||
candleStickChartLayer.container.eventHandler.raiseEvent("Current Candle Info Changed", currentCandle);
|
||||
|
||||
} else {
|
||||
|
||||
if (candle.direction === 'up') { browserCanvasContext.fillStyle = 'rgba(64, 217, 26, 1)'; }
|
||||
if (candle.direction === 'down') { browserCanvasContext.fillStyle = 'rgba(219, 18, 18, 1)'; }
|
||||
if (candle.direction === 'side') { browserCanvasContext.fillStyle = 'rgba(64, 26, 217, 1)'; }
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (candle.direction === 'up') { browserCanvasContext.fillStyle = 'rgba(64, 217, 26, 1)'; }
|
||||
if (candle.direction === 'down') { browserCanvasContext.fillStyle = 'rgba(219, 18, 18, 1)'; }
|
||||
if (candle.direction === 'side') { browserCanvasContext.fillStyle = 'rgba(64, 26, 217, 1)'; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (
|
||||
candlePoint1.x < viewPort.visibleArea.topLeft.x + 50
|
||||
||
|
||||
candlePoint1.x > viewPort.visibleArea.bottomRight.x - 50
|
||||
) {
|
||||
// we leave this candles without fill.
|
||||
} else {
|
||||
browserCanvasContext.fill();
|
||||
}
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,364 +0,0 @@
|
||||
|
||||
function newCandleTechnicalAnalisysChartLayer() {
|
||||
|
||||
|
||||
var candles = [];
|
||||
let timePeriod = INITIAL_TIME_PERIOD;
|
||||
|
||||
var plotArea = newPlotArea();
|
||||
|
||||
var datetime = INITIAL_DATE;
|
||||
|
||||
var candleTechnicalAnalisysChartLayer = {
|
||||
onLayerStatusChanged: onLayerStatusChanged,
|
||||
onCandlesChanged: onCandlesChanged,
|
||||
setTimePeriod: setTimePeriod,
|
||||
setDatetime: setDatetime,
|
||||
container: undefined,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
var container = newContainer();
|
||||
container.initialize();
|
||||
candleTechnicalAnalisysChartLayer.container = container;
|
||||
|
||||
container.displacement.containerName = "Candle Technical Analisys Chart";
|
||||
container.zoom.containerName = "Candle Technical Analisys Chart";
|
||||
container.frame.containerName = "Candle Technical Analisys Chart";
|
||||
|
||||
let marketId;
|
||||
let exchangeId;
|
||||
|
||||
let marketIndex;
|
||||
let dailyFilesCursor;
|
||||
|
||||
let stairsArray = [];
|
||||
|
||||
let layerStatus = 'off';
|
||||
let parentLayerStatus = 'off';
|
||||
|
||||
return candleTechnicalAnalisysChartLayer;
|
||||
|
||||
function initialize(exchange, market, index, dailyFiles, botsPanel) {
|
||||
|
||||
marketId = market;
|
||||
exchangeId = exchange;
|
||||
|
||||
marketIndex = index;
|
||||
dailyFilesCursor = dailyFiles;
|
||||
|
||||
recalculateScale();
|
||||
|
||||
layerStatus = botsPanel.getProductStatus(botsPanel.layerNames.CANDLE_STAIRS);
|
||||
parentLayerStatus = botsPanel.getProductStatus(botsPanel.layerNames.CANDLESTICKS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getContainer(point) {
|
||||
|
||||
var container;
|
||||
|
||||
/* First we check if this point is inside this space. */
|
||||
|
||||
if (this.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return this.container;
|
||||
|
||||
} else {
|
||||
|
||||
/* This point does not belong to this space. */
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function onLayerStatusChanged(eventData) {
|
||||
|
||||
if (eventData.layer === 'Candlesticks') {
|
||||
parentLayerStatus = eventData.status;
|
||||
}
|
||||
|
||||
if (eventData.layer === 'Candle Stairs') {
|
||||
layerStatus = eventData.status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function onCandlesChanged(newCandles) {
|
||||
|
||||
candles = newCandles;
|
||||
recalculatePatterns();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function setTimePeriod(period) {
|
||||
|
||||
timePeriod = period;
|
||||
|
||||
}
|
||||
|
||||
function setDatetime(newDatetime) {
|
||||
datetime = newDatetime;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
if (layerStatus !== 'on') { return; }
|
||||
|
||||
if (parentLayerStatus === 'off') { return; }
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
plotPatternChart();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculatePatterns() {
|
||||
|
||||
if (layerStatus === 'off') { return; }
|
||||
|
||||
if (parentLayerStatus === 'off') { return; }
|
||||
|
||||
/* Finding stairs */
|
||||
stairsArray = [];
|
||||
let stairs;
|
||||
|
||||
for (let i = 0; i < candles.length - 1; i++) {
|
||||
|
||||
let currentCandle = candles[i];
|
||||
let nextCandle = candles[i + 1];
|
||||
|
||||
if (currentCandle.direction === nextCandle.direction && currentCandle.direction !== 'side') {
|
||||
|
||||
if (stairs === undefined) {
|
||||
|
||||
stairs = newCandleStairs();
|
||||
|
||||
stairs.direction = currentCandle.direction;
|
||||
stairs.candleCount = 2;
|
||||
|
||||
stairs.begin = currentCandle.begin;
|
||||
stairs.end = nextCandle.end;
|
||||
|
||||
stairs.open = currentCandle.open;
|
||||
stairs.close = nextCandle.close;
|
||||
|
||||
if (currentCandle.min < nextCandle.min) { stairs.min = currentCandle.min; } else { stairs.min = nextCandle.min; }
|
||||
if (currentCandle.max > nextCandle.max) { stairs.max = currentCandle.max; } else { stairs.max = nextCandle.max; }
|
||||
|
||||
if (stairs.direction === 'up') {
|
||||
|
||||
stairs.firstMin = currentCandle.open;
|
||||
stairs.firstMax = currentCandle.close;
|
||||
|
||||
stairs.lastMin = nextCandle.open;
|
||||
stairs.lastMax = nextCandle.close;
|
||||
|
||||
} else {
|
||||
|
||||
stairs.firstMin = currentCandle.close;
|
||||
stairs.firstMax = currentCandle.open;
|
||||
|
||||
stairs.lastMin = nextCandle.close;
|
||||
stairs.lastMax = nextCandle.open;
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
stairs.candleCount++;
|
||||
stairs.end = nextCandle.end;
|
||||
stairs.close = nextCandle.close;
|
||||
|
||||
if (stairs.min < nextCandle.min) { stairs.min = currentCandle.min; }
|
||||
if (stairs.max > nextCandle.max) { stairs.max = currentCandle.max; }
|
||||
|
||||
if (stairs.direction === 'up') {
|
||||
|
||||
stairs.lastMin = nextCandle.open;
|
||||
stairs.lastMax = nextCandle.close;
|
||||
|
||||
} else {
|
||||
|
||||
stairs.lastMin = nextCandle.close;
|
||||
stairs.lastMax = nextCandle.open;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (stairs !== undefined) {
|
||||
stairsArray.push(stairs);
|
||||
stairs = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function recalculateScale() {
|
||||
|
||||
var minValue = {
|
||||
x: EARLIEST_DATE.valueOf(),
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf(),
|
||||
y: nextPorwerOf10(marketIndex.maxRate())
|
||||
};
|
||||
|
||||
|
||||
plotArea.initialize(
|
||||
minValue,
|
||||
maxValue,
|
||||
candleTechnicalAnalisysChartLayer.container.frame.width,
|
||||
candleTechnicalAnalisysChartLayer.container.frame.height
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function plotPatternChart() {
|
||||
|
||||
if (stairsArray.length > 0) {
|
||||
|
||||
for (var i = 0; i < stairsArray.length; i++) {
|
||||
|
||||
stairs = stairsArray[i];
|
||||
|
||||
let stairsPoint1;
|
||||
let stairsPoint2;
|
||||
let stairsPoint3;
|
||||
let stairsPoint4;
|
||||
|
||||
if (stairs.direction === 'up') {
|
||||
|
||||
stairsPoint1 = {
|
||||
x: stairs.begin + timePeriod / 7 * 5.5,
|
||||
y: stairs.firstMin
|
||||
};
|
||||
|
||||
stairsPoint2 = {
|
||||
x: stairs.end - timePeriod / 7 * 1.5,
|
||||
y: stairs.lastMin
|
||||
};
|
||||
|
||||
stairsPoint3 = {
|
||||
x: stairs.end - timePeriod / 7 * 5.5,
|
||||
y: stairs.lastMax
|
||||
};
|
||||
|
||||
stairsPoint4 = {
|
||||
x: stairs.begin + timePeriod / 7 * 1.5,
|
||||
y: stairs.firstMax
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
stairsPoint1 = {
|
||||
x: stairs.begin + timePeriod / 7 * 1.5,
|
||||
y: stairs.firstMin
|
||||
};
|
||||
|
||||
stairsPoint2 = {
|
||||
x: stairs.end - timePeriod / 7 * 5.5,
|
||||
y: stairs.lastMin
|
||||
};
|
||||
|
||||
stairsPoint3 = {
|
||||
x: stairs.end - timePeriod / 7 * 1.5,
|
||||
y: stairs.lastMax
|
||||
};
|
||||
|
||||
stairsPoint4 = {
|
||||
x: stairs.begin + timePeriod / 7 * 5.5,
|
||||
y: stairs.firstMax
|
||||
};
|
||||
}
|
||||
|
||||
stairsPoint1 = plotArea.inverseTransform(stairsPoint1, candleTechnicalAnalisysChartLayer.container.frame.height);
|
||||
stairsPoint2 = plotArea.inverseTransform(stairsPoint2, candleTechnicalAnalisysChartLayer.container.frame.height);
|
||||
stairsPoint3 = plotArea.inverseTransform(stairsPoint3, candleTechnicalAnalisysChartLayer.container.frame.height);
|
||||
stairsPoint4 = plotArea.inverseTransform(stairsPoint4, candleTechnicalAnalisysChartLayer.container.frame.height);
|
||||
|
||||
stairsPoint1 = transformThisPoint(stairsPoint1, candleTechnicalAnalisysChartLayer.container);
|
||||
stairsPoint2 = transformThisPoint(stairsPoint2, candleTechnicalAnalisysChartLayer.container);
|
||||
stairsPoint3 = transformThisPoint(stairsPoint3, candleTechnicalAnalisysChartLayer.container);
|
||||
stairsPoint4 = transformThisPoint(stairsPoint4, candleTechnicalAnalisysChartLayer.container);
|
||||
|
||||
if (stairsPoint2.x < viewPort.visibleArea.bottomLeft.x || stairsPoint1.x > viewPort.visibleArea.bottomRight.x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stairsPoint1 = viewPort.fitIntoVisibleArea(stairsPoint1);
|
||||
stairsPoint2 = viewPort.fitIntoVisibleArea(stairsPoint2);
|
||||
stairsPoint3 = viewPort.fitIntoVisibleArea(stairsPoint3);
|
||||
stairsPoint4 = viewPort.fitIntoVisibleArea(stairsPoint4);
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(stairsPoint1.x, stairsPoint1.y);
|
||||
browserCanvasContext.lineTo(stairsPoint2.x, stairsPoint2.y);
|
||||
browserCanvasContext.lineTo(stairsPoint3.x, stairsPoint3.y);
|
||||
browserCanvasContext.lineTo(stairsPoint4.x, stairsPoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
let opacity = '0.25';
|
||||
|
||||
if (stairs.direction === 'up') { browserCanvasContext.strokeStyle = 'rgba(27, 105, 7, ' + opacity + ')'; }
|
||||
if (stairs.direction === 'down') { browserCanvasContext.strokeStyle = 'rgba(130, 9, 9, ' + opacity + ')'; }
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= stairs.begin && dateValue <= stairs.end) {
|
||||
|
||||
|
||||
/* highlight the current stairs */
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, 0.1)'; // Current stairs accroding to time
|
||||
|
||||
} else {
|
||||
|
||||
if (stairs.direction === 'up') { browserCanvasContext.fillStyle = 'rgba(64, 217, 26, ' + opacity + ')'; }
|
||||
if (stairs.direction === 'down') { browserCanvasContext.fillStyle = 'rgba(219, 18, 18, ' + opacity + ')'; }
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (stairs.direction === 'up') { browserCanvasContext.fillStyle = 'rgba(64, 217, 26, ' + opacity + ')'; }
|
||||
if (stairs.direction === 'down') { browserCanvasContext.fillStyle = 'rgba(219, 18, 18, ' + opacity + ')'; }
|
||||
}
|
||||
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,484 +0,0 @@
|
||||
|
||||
function newForecastChartLayer() {
|
||||
|
||||
|
||||
let candles = [];
|
||||
let timePeriod = INITIAL_TIME_PERIOD;
|
||||
|
||||
let plotArea = newPlotArea();
|
||||
|
||||
var datetime = INITIAL_DATE;
|
||||
|
||||
let forecastChartLayer = {
|
||||
onLayerStatusChanged: onLayerStatusChanged,
|
||||
setTimePeriod: setTimePeriod,
|
||||
setDatetime: setDatetime,
|
||||
setCurrentCandle: setCurrentCandle,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
var container = newContainer();
|
||||
container.initialize();
|
||||
forecastChartLayer.container = container;
|
||||
|
||||
container.displacement.containerName = "Forecast Chart";
|
||||
container.zoom.containerName = "Forecast Chart";
|
||||
container.frame.containerName = "Forecast Chart";
|
||||
|
||||
let marketId;
|
||||
let exchangeId;
|
||||
|
||||
let marketIndex;
|
||||
let dailyFilesCursor;
|
||||
|
||||
let forecastCandles = [];
|
||||
let currentCandle;
|
||||
|
||||
let layerStatus = 'off';
|
||||
let parentLayerStatus = 'off';
|
||||
|
||||
return forecastChartLayer;
|
||||
|
||||
function initialize(exchange, market, index, dailyFiles, botsPanel) {
|
||||
|
||||
marketId = market;
|
||||
exchangeId = exchange;
|
||||
|
||||
marketIndex = index;
|
||||
dailyFilesCursor = dailyFiles;
|
||||
|
||||
recalculateScale();
|
||||
|
||||
viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged);
|
||||
canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished);
|
||||
|
||||
layerStatus = botsPanel.getProductStatus(botsPanel.layerNames.FORECAST);
|
||||
parentLayerStatus = botsPanel.getProductStatus(botsPanel.layerNames.CANDLESTICKS);
|
||||
|
||||
}
|
||||
|
||||
function getContainer(point) {
|
||||
|
||||
var container;
|
||||
|
||||
/* First we check if this point is inside this space. */
|
||||
|
||||
if (this.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return this.container;
|
||||
|
||||
} else {
|
||||
|
||||
/* This point does not belong to this space. */
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onLayerStatusChanged(eventData) {
|
||||
|
||||
if (eventData.layer === 'Candlesticks') {
|
||||
parentLayerStatus = eventData.status;
|
||||
}
|
||||
|
||||
if (eventData.layer === 'Forecast') {
|
||||
layerStatus = eventData.status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onZoomChanged(event) {
|
||||
|
||||
//recalculateCandles();
|
||||
|
||||
}
|
||||
|
||||
function onDragFinished() {
|
||||
|
||||
if (timePeriod !== ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
//recalculateCandles();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function setTimePeriod(period) {
|
||||
|
||||
timePeriod = period;
|
||||
}
|
||||
|
||||
|
||||
function setCurrentCandle(newCurrentCandle) {
|
||||
|
||||
currentCandle = newCurrentCandle;
|
||||
recalculateForecastCandles();
|
||||
recalculateCandles();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function setDatetime(newDatetime) {
|
||||
datetime = newDatetime;
|
||||
}
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
if (layerStatus !== 'on') { return; }
|
||||
|
||||
if (parentLayerStatus === 'off') { return; }
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
if (timePeriod !== ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
plotCandleChart();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function recalculateForecastCandles() {
|
||||
|
||||
if (layerStatus === 'off') { return; }
|
||||
|
||||
if (parentLayerStatus === 'off') { return; }
|
||||
|
||||
if (timePeriod < _5_MINUTES_IN_MILISECONDS || timePeriod > _1_HOUR_IN_MILISECONDS) {
|
||||
|
||||
forecastCandles = [];
|
||||
candles = [];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let daysOnSides = 30;
|
||||
|
||||
let leftDate;
|
||||
let rightDate;
|
||||
|
||||
leftDate = getDateFromPoint(viewPort.visibleArea.topLeft, forecastChartLayer.container, plotArea);
|
||||
rightDate = new Date(leftDate.getTime());
|
||||
|
||||
leftDate.setDate(leftDate.getDate() - daysOnSides);
|
||||
|
||||
let currentDate = new Date(leftDate.getTime());
|
||||
|
||||
forecastCandles = [];
|
||||
let clonned = 0;
|
||||
let clonningCandles = false;
|
||||
let candleDistance;
|
||||
|
||||
while (currentDate.getTime() <= rightDate.getTime()) {
|
||||
|
||||
let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2);
|
||||
|
||||
let dailyFile = dailyFilesCursor.dailyFiles.get(stringDate);
|
||||
|
||||
if (dailyFile !== undefined) {
|
||||
|
||||
const totalCandles = dailyFile.length;
|
||||
|
||||
for (var i = 0; i < totalCandles; i++) {
|
||||
|
||||
var candle = newCandle();
|
||||
|
||||
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];
|
||||
|
||||
candle.beginId = dailyFile[i][6];
|
||||
candle.endId = dailyFile[i][7];
|
||||
|
||||
if (clonningCandles === false && currentCandle.open > candle.open - candle.open * 0.001 && currentCandle.open < candle.open + candle.open * 0.001) {
|
||||
|
||||
clonningCandles = true;
|
||||
candleDistance = currentCandle.end - candle.begin;
|
||||
|
||||
}
|
||||
|
||||
if (clonningCandles === true) {
|
||||
|
||||
candle.begin = candle.begin + candleDistance;
|
||||
candle.end = candle.end + candleDistance;
|
||||
|
||||
forecastCandles.push(candle);
|
||||
|
||||
clonned++;
|
||||
|
||||
if (clonned === Math.trunc(totalCandles / 2)) {
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function recalculateCandles() {
|
||||
|
||||
try {
|
||||
|
||||
candles = [];
|
||||
|
||||
const fileTimePeriod = 60 * 1000;
|
||||
const totalCandles = forecastCandles.length * fileTimePeriod / timePeriod;
|
||||
const recordsPerCandle = timePeriod / fileTimePeriod;
|
||||
|
||||
for (var i = 0; i < totalCandles; i++) {
|
||||
|
||||
var candle = newCandle();
|
||||
|
||||
let min = forecastCandles[i * recordsPerCandle].min;
|
||||
let max = forecastCandles[i * recordsPerCandle].max;
|
||||
|
||||
for (var j = 0; j < recordsPerCandle; j++) {
|
||||
|
||||
|
||||
|
||||
if (forecastCandles[i * recordsPerCandle + j].min < min) {
|
||||
|
||||
min = forecastCandles[i * recordsPerCandle + j].min;
|
||||
}
|
||||
|
||||
if (forecastCandles[i * recordsPerCandle + j][1] > max) {
|
||||
|
||||
max = forecastCandles[i * recordsPerCandle + j].max;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
candle.min = min;
|
||||
candle.max = max;
|
||||
|
||||
candle.open = forecastCandles[i * recordsPerCandle].open;
|
||||
candle.close = forecastCandles[i * recordsPerCandle + recordsPerCandle - 1].close;
|
||||
|
||||
candle.begin = forecastCandles[i * recordsPerCandle].begin;
|
||||
candle.end = forecastCandles[i * recordsPerCandle + recordsPerCandle - 1].end;
|
||||
|
||||
candle.beginId = forecastCandles[i * recordsPerCandle].beginId;
|
||||
candle.endId = forecastCandles[i * recordsPerCandle + recordsPerCandle - 1].endId;
|
||||
|
||||
candles.push(candle);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
let errorDescription = err; // For now, if there is some problem we just dont have a forecast, or a complete one.
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function recalculateScale() {
|
||||
|
||||
var minValue = {
|
||||
x: EARLIEST_DATE.valueOf(),
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf(),
|
||||
y: nextPorwerOf10(marketIndex.maxRate())
|
||||
};
|
||||
|
||||
|
||||
plotArea.initialize(
|
||||
minValue,
|
||||
maxValue,
|
||||
forecastChartLayer.container.frame.width,
|
||||
forecastChartLayer.container.frame.height
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function plotCandleChart() {
|
||||
|
||||
if (candles.length > 0) {
|
||||
|
||||
/* Now we calculate and plot the candles */
|
||||
|
||||
for (var i = 0; i < candles.length; i++) {
|
||||
|
||||
let candleOpacity = 0.5 - i / candles.length;
|
||||
|
||||
if (candleOpacity < 0) {
|
||||
candleOpacity = 0;
|
||||
}
|
||||
|
||||
let stickOpacity = 0.25 - i / candles.length * 2;
|
||||
|
||||
if (stickOpacity < 0) {
|
||||
stickOpacity = 0;
|
||||
}
|
||||
|
||||
candle = candles[i];
|
||||
|
||||
var candlePoint1 = {
|
||||
x: candle.begin + timePeriod / 7 * 1.5,
|
||||
y: candle.open
|
||||
};
|
||||
|
||||
var candlePoint2 = {
|
||||
x: candle.begin + timePeriod / 7 * 5.5,
|
||||
y: candle.open
|
||||
};
|
||||
|
||||
var candlePoint3 = {
|
||||
x: candle.begin + timePeriod / 7 * 5.5,
|
||||
y: candle.close
|
||||
};
|
||||
|
||||
var candlePoint4 = {
|
||||
x: candle.begin + timePeriod / 7 * 1.5,
|
||||
y: candle.close
|
||||
};
|
||||
|
||||
candlePoint1 = plotArea.inverseTransform(candlePoint1, forecastChartLayer.container.frame.height);
|
||||
candlePoint2 = plotArea.inverseTransform(candlePoint2, forecastChartLayer.container.frame.height);
|
||||
candlePoint3 = plotArea.inverseTransform(candlePoint3, forecastChartLayer.container.frame.height);
|
||||
candlePoint4 = plotArea.inverseTransform(candlePoint4, forecastChartLayer.container.frame.height);
|
||||
|
||||
candlePoint1 = transformThisPoint(candlePoint1, forecastChartLayer.container);
|
||||
candlePoint2 = transformThisPoint(candlePoint2, forecastChartLayer.container);
|
||||
candlePoint3 = transformThisPoint(candlePoint3, forecastChartLayer.container);
|
||||
candlePoint4 = transformThisPoint(candlePoint4, forecastChartLayer.container);
|
||||
|
||||
candlePoint1 = viewPort.fitIntoVisibleArea(candlePoint1);
|
||||
candlePoint2 = viewPort.fitIntoVisibleArea(candlePoint2);
|
||||
candlePoint3 = viewPort.fitIntoVisibleArea(candlePoint3);
|
||||
candlePoint4 = viewPort.fitIntoVisibleArea(candlePoint4);
|
||||
|
||||
if (candlePoint2.x < viewPort.visibleArea.bottomLeft.x || candlePoint1.x > viewPort.visibleArea.bottomRight.x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var stickPoint1 = {
|
||||
x: candle.begin + timePeriod / 7 * 3.2,
|
||||
y: candle.max
|
||||
};
|
||||
|
||||
var stickPoint2 = {
|
||||
x: candle.begin + timePeriod / 7 * 3.8,
|
||||
y: candle.max
|
||||
};
|
||||
|
||||
var stickPoint3 = {
|
||||
x: candle.begin + timePeriod / 7 * 3.8,
|
||||
y: candle.min
|
||||
};
|
||||
|
||||
var stickPoint4 = {
|
||||
x: candle.begin + timePeriod / 7 * 3.2,
|
||||
y: candle.min
|
||||
};
|
||||
|
||||
stickPoint1 = plotArea.inverseTransform(stickPoint1, forecastChartLayer.container.frame.height);
|
||||
stickPoint2 = plotArea.inverseTransform(stickPoint2, forecastChartLayer.container.frame.height);
|
||||
stickPoint3 = plotArea.inverseTransform(stickPoint3, forecastChartLayer.container.frame.height);
|
||||
stickPoint4 = plotArea.inverseTransform(stickPoint4, forecastChartLayer.container.frame.height);
|
||||
|
||||
stickPoint1 = transformThisPoint(stickPoint1, forecastChartLayer.container);
|
||||
stickPoint2 = transformThisPoint(stickPoint2, forecastChartLayer.container);
|
||||
stickPoint3 = transformThisPoint(stickPoint3, forecastChartLayer.container);
|
||||
stickPoint4 = transformThisPoint(stickPoint4, forecastChartLayer.container);
|
||||
|
||||
stickPoint1 = viewPort.fitIntoVisibleArea(stickPoint1);
|
||||
stickPoint2 = viewPort.fitIntoVisibleArea(stickPoint2);
|
||||
stickPoint3 = viewPort.fitIntoVisibleArea(stickPoint3);
|
||||
stickPoint4 = viewPort.fitIntoVisibleArea(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(54, 54, 54, ' + stickOpacity + ')';
|
||||
browserCanvasContext.fill();
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= candle.begin && dateValue <= candle.end) {
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(255, 233, 31, ' + stickOpacity + ')'; // Current candle accroding to time
|
||||
currentCandle = i;
|
||||
|
||||
} else {
|
||||
browserCanvasContext.strokeStyle = 'rgba(212, 206, 201, ' + stickOpacity + ')';
|
||||
}
|
||||
|
||||
} else {
|
||||
browserCanvasContext.strokeStyle = 'rgba(212, 206, 201, ' + stickOpacity + ')';
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (candle.open < candle.close) {
|
||||
browserCanvasContext.strokeStyle = 'rgba(27, 145, 143, ' + candleOpacity + ')';
|
||||
} else {
|
||||
browserCanvasContext.strokeStyle = 'rgba(30, 28, 119, ' + candleOpacity + ')';
|
||||
}
|
||||
|
||||
if (candle.open < candle.close) {
|
||||
browserCanvasContext.fillStyle = 'rgba(49, 247, 244, ' + candleOpacity + ')';
|
||||
} else {
|
||||
browserCanvasContext.fillStyle = 'rgba(28, 22, 226, ' + candleOpacity + ')';
|
||||
}
|
||||
|
||||
if (
|
||||
candlePoint1.x < viewPort.visibleArea.topLeft.x + 50
|
||||
||
|
||||
candlePoint1.x > viewPort.visibleArea.bottomRight.x - 50
|
||||
) {
|
||||
// we leave this candles without fill.
|
||||
} else {
|
||||
browserCanvasContext.fill();
|
||||
}
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,587 +0,0 @@
|
||||
|
||||
function newHighLowChartLayer() {
|
||||
|
||||
|
||||
var candles = [];
|
||||
let timePeriod = INITIAL_TIME_PERIOD;
|
||||
|
||||
var plotArea = newPlotArea();
|
||||
|
||||
var datetime = INITIAL_DATE;
|
||||
|
||||
var highLowChartLayer = {
|
||||
onLayerStatusChanged: onLayerStatusChanged,
|
||||
onCandlesChanged: onCandlesChanged,
|
||||
setTimePeriod: setTimePeriod,
|
||||
setDatetime: setDatetime,
|
||||
container: undefined,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
var container = newContainer();
|
||||
container.initialize();
|
||||
highLowChartLayer.container = container;
|
||||
|
||||
container.displacement.containerName = "Candle Stick Chart";
|
||||
container.zoom.containerName = "Candle Stick Chart";
|
||||
container.frame.containerName = "Candle Stick Chart";
|
||||
|
||||
let marketId;
|
||||
let exchangeId;
|
||||
|
||||
let marketIndex;
|
||||
let dailyFilesCursor;
|
||||
|
||||
let highLowFlagArray = [];
|
||||
|
||||
let layerStatus = 'off';
|
||||
let parentLayerStatus = 'off';
|
||||
|
||||
return highLowChartLayer;
|
||||
|
||||
function initialize(exchange, market, index, dailyFiles, botsPanel) {
|
||||
|
||||
marketId = market;
|
||||
exchangeId = exchange;
|
||||
|
||||
marketIndex = index;
|
||||
dailyFilesCursor = dailyFiles;
|
||||
|
||||
recalculateScale();
|
||||
|
||||
layerStatus = botsPanel.getProductStatus(botsPanel.layerNames.HIGH_LOWS);
|
||||
parentLayerStatus = botsPanel.getProductStatus(botsPanel.layerNames.CANDLESTICKS);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getContainer(point) {
|
||||
|
||||
var container;
|
||||
|
||||
/* First we check if this point is inside this space. */
|
||||
|
||||
if (this.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return this.container;
|
||||
|
||||
} else {
|
||||
|
||||
/* This point does not belong to this space. */
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onLayerStatusChanged(eventData) {
|
||||
|
||||
if (eventData.layer === 'Candlesticks') {
|
||||
parentLayerStatus = eventData.status;
|
||||
}
|
||||
|
||||
if (eventData.layer === 'High and Lows') {
|
||||
layerStatus = eventData.status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onCandlesChanged(newCandles) {
|
||||
|
||||
candles = newCandles;
|
||||
recalculateHighLow();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function setTimePeriod(period) {
|
||||
|
||||
timePeriod = period;
|
||||
|
||||
}
|
||||
|
||||
function setDatetime(newDatetime) {
|
||||
datetime = newDatetime;
|
||||
recalculateHighLow();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
if (layerStatus !== 'on') { return; }
|
||||
|
||||
if (parentLayerStatus === 'off') { return; }
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
plotHighLowChart();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateHighLow() {
|
||||
|
||||
if (layerStatus === 'off') { return; }
|
||||
|
||||
if (parentLayerStatus === 'off') { return; }
|
||||
|
||||
highLowFlagArray = [];
|
||||
|
||||
for (let i = 0; i < candles.length - 2; i++) {
|
||||
|
||||
let previousCandle = candles[i];
|
||||
let currentCandle = candles[i + 1];
|
||||
let nextCandle = candles[i + 2];
|
||||
|
||||
if (currentCandle.max >= previousCandle.max && currentCandle.max >= nextCandle.max) {
|
||||
|
||||
let highLowFlag = newHighLowFlag();
|
||||
|
||||
highLowFlag.rate = currentCandle.max;
|
||||
highLowFlag.type = 'max-high';
|
||||
|
||||
highLowFlag.begin = currentCandle.begin;
|
||||
highLowFlag.end = currentCandle.end;
|
||||
|
||||
let scanIndex;
|
||||
|
||||
scanIndex= i + 1;
|
||||
|
||||
while (scanIndex > 0) {
|
||||
|
||||
scanIndex--;
|
||||
let scanCandle = candles[scanIndex];
|
||||
|
||||
if (currentCandle.max >= scanCandle.max) {
|
||||
|
||||
highLowFlag.firstBegin = scanCandle.begin;
|
||||
highLowFlag.pastCandles++;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
scanIndex = i + 1;
|
||||
|
||||
while (scanIndex < candles.length - 1) {
|
||||
|
||||
scanIndex++;
|
||||
let scanCandle = candles[scanIndex];
|
||||
|
||||
if (currentCandle.max >= scanCandle.max) {
|
||||
|
||||
highLowFlag.lastEnd = scanCandle.end;
|
||||
highLowFlag.futureCandles++;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (highLowFlag.pastCandles >= 1 && highLowFlag.futureCandles >= 1) {
|
||||
|
||||
highLowFlagArray.push(highLowFlag);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (currentCandle.min <= previousCandle.min && currentCandle.min <= nextCandle.min) {
|
||||
|
||||
let highLowFlag = newHighLowFlag();
|
||||
|
||||
highLowFlag.rate = currentCandle.min;
|
||||
highLowFlag.type = 'min-low';
|
||||
|
||||
highLowFlag.begin = currentCandle.begin;
|
||||
highLowFlag.end = currentCandle.end;
|
||||
|
||||
let scanIndex;
|
||||
|
||||
scanIndex = i + 1;
|
||||
|
||||
while (scanIndex > 0) {
|
||||
|
||||
scanIndex--;
|
||||
let scanCandle = candles[scanIndex];
|
||||
|
||||
if (currentCandle.min <= scanCandle.min) {
|
||||
|
||||
highLowFlag.firstBegin = scanCandle.begin;
|
||||
highLowFlag.pastCandles++;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
scanIndex = i + 1;
|
||||
|
||||
while (scanIndex < candles.length - 1) {
|
||||
|
||||
scanIndex++;
|
||||
let scanCandle = candles[scanIndex];
|
||||
|
||||
if (currentCandle.min <= scanCandle.min) {
|
||||
|
||||
highLowFlag.lastEnd = scanCandle.end;
|
||||
highLowFlag.futureCandles++;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (highLowFlag.pastCandles >= 1 && highLowFlag.futureCandles >= 1) {
|
||||
|
||||
highLowFlagArray.push(highLowFlag);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentCandle.max <= previousCandle.max && currentCandle.max <= nextCandle.max) {
|
||||
|
||||
let highLowFlag = newHighLowFlag();
|
||||
|
||||
highLowFlag.rate = currentCandle.max;
|
||||
highLowFlag.type = 'min-high';
|
||||
|
||||
highLowFlag.begin = currentCandle.begin;
|
||||
highLowFlag.end = currentCandle.end;
|
||||
|
||||
let scanIndex;
|
||||
|
||||
scanIndex = i + 1;
|
||||
|
||||
while (scanIndex > 0) {
|
||||
|
||||
scanIndex--;
|
||||
let scanCandle = candles[scanIndex];
|
||||
|
||||
if (currentCandle.max <= scanCandle.max) {
|
||||
|
||||
highLowFlag.firstBegin = scanCandle.begin;
|
||||
highLowFlag.pastCandles++;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
scanIndex = i + 1;
|
||||
|
||||
while (scanIndex < candles.length - 1) {
|
||||
|
||||
scanIndex++;
|
||||
let scanCandle = candles[scanIndex];
|
||||
|
||||
if (currentCandle.max <= scanCandle.max) {
|
||||
|
||||
highLowFlag.lastEnd = scanCandle.end;
|
||||
highLowFlag.futureCandles++;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (highLowFlag.pastCandles >= 1 && highLowFlag.futureCandles >= 1) {
|
||||
|
||||
highLowFlagArray.push(highLowFlag);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (currentCandle.min >= previousCandle.min && currentCandle.min >= nextCandle.min) {
|
||||
|
||||
let highLowFlag = newHighLowFlag();
|
||||
|
||||
highLowFlag.rate = currentCandle.min;
|
||||
highLowFlag.type = 'max-low';
|
||||
|
||||
highLowFlag.begin = currentCandle.begin;
|
||||
highLowFlag.end = currentCandle.end;
|
||||
|
||||
let scanIndex;
|
||||
|
||||
scanIndex = i + 1;
|
||||
|
||||
while (scanIndex > 0) {
|
||||
|
||||
scanIndex--;
|
||||
let scanCandle = candles[scanIndex];
|
||||
|
||||
if (currentCandle.min >= scanCandle.min) {
|
||||
|
||||
highLowFlag.firstBegin = scanCandle.begin;
|
||||
highLowFlag.pastCandles++;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
scanIndex = i + 1;
|
||||
|
||||
while (scanIndex < candles.length - 1) {
|
||||
|
||||
scanIndex++;
|
||||
let scanCandle = candles[scanIndex];
|
||||
|
||||
if (currentCandle.min >= scanCandle.min) {
|
||||
|
||||
highLowFlag.lastEnd = scanCandle.end;
|
||||
highLowFlag.futureCandles++;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (highLowFlag.pastCandles >= 1 && highLowFlag.futureCandles >= 1) {
|
||||
|
||||
highLowFlagArray.push(highLowFlag);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function recalculateScale() {
|
||||
|
||||
var minValue = {
|
||||
x: EARLIEST_DATE.valueOf(),
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf(),
|
||||
y: nextPorwerOf10(marketIndex.maxRate())
|
||||
};
|
||||
|
||||
|
||||
plotArea.initialize(
|
||||
minValue,
|
||||
maxValue,
|
||||
highLowChartLayer.container.frame.width,
|
||||
highLowChartLayer.container.frame.height
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function plotHighLowChart() {
|
||||
|
||||
if (highLowFlagArray.length > 0) {
|
||||
|
||||
for (var i = 0; i < highLowFlagArray.length; i++) {
|
||||
|
||||
flag = highLowFlagArray[i];
|
||||
|
||||
let flagPoint1;
|
||||
let flagPoint2;
|
||||
let flagPoint3;
|
||||
let flagPoint4;
|
||||
let flagPoint5;
|
||||
let flagPoint6;
|
||||
|
||||
flagPoint1 = {
|
||||
x: flag.begin + timePeriod / 2,
|
||||
y: flag.rate
|
||||
};
|
||||
|
||||
flagPoint2 = {
|
||||
x: flag.lastEnd,
|
||||
y: flag.rate
|
||||
};
|
||||
|
||||
flagPoint3 = {
|
||||
x: flag.begin + timePeriod / 2,
|
||||
y: flag.rate
|
||||
};
|
||||
|
||||
flagPoint4 = {
|
||||
x: flag.begin + timePeriod / 2,
|
||||
y: flag.rate
|
||||
};
|
||||
|
||||
flagPoint5 = {
|
||||
x: flag.begin + timePeriod / 2,
|
||||
y: flag.rate
|
||||
};
|
||||
|
||||
flagPoint6 = {
|
||||
x: flag.begin + timePeriod / 2,
|
||||
y: flag.rate
|
||||
};
|
||||
|
||||
flagPoint7 = {
|
||||
x: flag.begin + timePeriod / 7 * 1.5,
|
||||
y: flag.rate
|
||||
};
|
||||
|
||||
flagPoint8 = {
|
||||
x: flag.begin + timePeriod / 7 * 5.5,
|
||||
y: flag.rate
|
||||
};
|
||||
|
||||
flagPoint1 = plotArea.inverseTransform(flagPoint1, highLowChartLayer.container.frame.height);
|
||||
flagPoint2 = plotArea.inverseTransform(flagPoint2, highLowChartLayer.container.frame.height);
|
||||
flagPoint3 = plotArea.inverseTransform(flagPoint3, highLowChartLayer.container.frame.height);
|
||||
flagPoint4 = plotArea.inverseTransform(flagPoint4, highLowChartLayer.container.frame.height);
|
||||
flagPoint5 = plotArea.inverseTransform(flagPoint5, highLowChartLayer.container.frame.height);
|
||||
flagPoint6 = plotArea.inverseTransform(flagPoint6, highLowChartLayer.container.frame.height);
|
||||
flagPoint7 = plotArea.inverseTransform(flagPoint7, highLowChartLayer.container.frame.height);
|
||||
flagPoint8 = plotArea.inverseTransform(flagPoint8, highLowChartLayer.container.frame.height);
|
||||
|
||||
flagPoint1 = transformThisPoint(flagPoint1, highLowChartLayer.container);
|
||||
flagPoint2 = transformThisPoint(flagPoint2, highLowChartLayer.container);
|
||||
flagPoint3 = transformThisPoint(flagPoint3, highLowChartLayer.container);
|
||||
flagPoint4 = transformThisPoint(flagPoint4, highLowChartLayer.container);
|
||||
flagPoint5 = transformThisPoint(flagPoint5, highLowChartLayer.container);
|
||||
flagPoint6 = transformThisPoint(flagPoint6, highLowChartLayer.container);
|
||||
flagPoint7 = transformThisPoint(flagPoint7, highLowChartLayer.container);
|
||||
flagPoint8 = transformThisPoint(flagPoint8, highLowChartLayer.container);
|
||||
|
||||
if (flagPoint2.x < viewPort.visibleArea.bottomLeft.x || flagPoint1.x > viewPort.visibleArea.bottomRight.x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let opacity = '0.50';
|
||||
let POLE_HEIGHT = (flagPoint8.x - flagPoint7.x);
|
||||
|
||||
|
||||
if (flag.type === 'max-high') {
|
||||
|
||||
flagPoint4.y = flagPoint4.y - POLE_HEIGHT;
|
||||
flagPoint5.y = flagPoint5.y - POLE_HEIGHT * 3 / 4;
|
||||
flagPoint6.y = flagPoint6.y - POLE_HEIGHT / 2;
|
||||
flagPoint5.x = flagPoint5.x + POLE_HEIGHT / 2;
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(27, 105, 7, ' + opacity + ')';
|
||||
browserCanvasContext.fillStyle = 'rgba(64, 217, 26, ' + opacity + ')';
|
||||
|
||||
}
|
||||
|
||||
if (flag.type === 'min-low') {
|
||||
|
||||
flagPoint4.y = flagPoint4.y + POLE_HEIGHT;
|
||||
flagPoint5.y = flagPoint5.y + POLE_HEIGHT * 3 / 4;
|
||||
flagPoint6.y = flagPoint6.y + POLE_HEIGHT / 2;
|
||||
flagPoint5.x = flagPoint5.x - POLE_HEIGHT / 2;
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(130, 9, 9, ' + opacity + ')';
|
||||
browserCanvasContext.fillStyle = 'rgba(219, 18, 18, ' + opacity + ')';
|
||||
|
||||
}
|
||||
|
||||
if (flag.type === 'min-high') {
|
||||
|
||||
flagPoint4.y = flagPoint4.y - POLE_HEIGHT;
|
||||
flagPoint5.y = flagPoint5.y - POLE_HEIGHT * 3 / 4;
|
||||
flagPoint6.y = flagPoint6.y - POLE_HEIGHT / 2;
|
||||
flagPoint5.x = flagPoint5.x - POLE_HEIGHT / 2;
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(27, 105, 7, ' + opacity + ')';
|
||||
browserCanvasContext.fillStyle = 'rgba(64, 217, 26, ' + opacity + ')';
|
||||
|
||||
}
|
||||
|
||||
if (flag.type === 'max-low') {
|
||||
|
||||
flagPoint4.y = flagPoint4.y + POLE_HEIGHT;
|
||||
flagPoint5.y = flagPoint5.y + POLE_HEIGHT * 3 / 4;
|
||||
flagPoint6.y = flagPoint6.y + POLE_HEIGHT / 2;
|
||||
flagPoint5.x = flagPoint5.x + POLE_HEIGHT / 2;
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(130, 9, 9, ' + opacity + ')';
|
||||
browserCanvasContext.fillStyle = 'rgba(219, 18, 18, ' + opacity + ')';
|
||||
|
||||
}
|
||||
|
||||
flagPoint1 = viewPort.fitIntoVisibleArea(flagPoint1);
|
||||
flagPoint2 = viewPort.fitIntoVisibleArea(flagPoint2);
|
||||
flagPoint3 = viewPort.fitIntoVisibleArea(flagPoint3);
|
||||
flagPoint4 = viewPort.fitIntoVisibleArea(flagPoint4);
|
||||
flagPoint5 = viewPort.fitIntoVisibleArea(flagPoint5);
|
||||
flagPoint6 = viewPort.fitIntoVisibleArea(flagPoint6);
|
||||
flagPoint7 = viewPort.fitIntoVisibleArea(flagPoint7);
|
||||
flagPoint8 = viewPort.fitIntoVisibleArea(flagPoint8);
|
||||
|
||||
if (flag.direction === 'up') { browserCanvasContext.strokeStyle = 'rgba(27, 105, 7, ' + opacity + ')'; }
|
||||
if (flag.direction === 'down') { browserCanvasContext.strokeStyle = 'rgba(130, 9, 9, ' + opacity + ')'; }
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= flag.begin && dateValue <= flag.end) {
|
||||
|
||||
/* highlight the current flag */
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, 0.1)'; // Current flag accroding to time
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw the flag body */
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(flagPoint4.x, flagPoint4.y);
|
||||
browserCanvasContext.lineTo(flagPoint5.x, flagPoint5.y);
|
||||
browserCanvasContext.lineTo(flagPoint6.x, flagPoint6.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.fill();
|
||||
|
||||
if (flag.type === 'max-high' || flag.type === 'min-low') {
|
||||
|
||||
/* Draw the multi candle line */
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(flagPoint1.x, flagPoint1.y);
|
||||
browserCanvasContext.lineTo(flagPoint2.x, flagPoint2.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.lineWidth = 0.1;
|
||||
browserCanvasContext.stroke();
|
||||
}
|
||||
|
||||
/* Draw the floor and the pole */
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(flagPoint3.x, flagPoint3.y);
|
||||
browserCanvasContext.lineTo(flagPoint4.x, flagPoint4.y);
|
||||
browserCanvasContext.lineTo(flagPoint5.x, flagPoint5.y);
|
||||
browserCanvasContext.lineTo(flagPoint6.x, flagPoint6.y);
|
||||
browserCanvasContext.moveTo(flagPoint7.x, flagPoint7.y);
|
||||
browserCanvasContext.lineTo(flagPoint8.x, flagPoint8.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
/**
|
||||
* Base File: CandleTechnicalAnalisysChartLayer.js
|
||||
*/
|
||||
function newLinearRegressionCurve() {
|
||||
var candles = [];
|
||||
let timePeriod = INITIAL_TIME_PERIOD;
|
||||
var plotArea = newPlotArea();
|
||||
var datetime = INITIAL_DATE;
|
||||
|
||||
var linearRegressionCurveChartLayer = {
|
||||
onLayerStatusChanged: onLayerStatusChanged,
|
||||
onCandlesChanged: onCandlesChanged,
|
||||
setTimePeriod: setTimePeriod,
|
||||
setDatetime: setDatetime,
|
||||
container: undefined,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
var container = newContainer();
|
||||
container.initialize();
|
||||
linearRegressionCurveChartLayer.container = container;
|
||||
|
||||
container.displacement.containerName = "Linear Regression Curve Chart";
|
||||
container.zoom.containerName = container.displacement.containerName;
|
||||
container.frame.containerName = container.displacement.containerName;
|
||||
|
||||
let marketId;
|
||||
let exchangeId;
|
||||
|
||||
let marketIndex;
|
||||
let dailyFilesCursor;
|
||||
|
||||
let LRCArray15 = [];
|
||||
let LRCArray30 = [];
|
||||
let LRCArray60 = [];
|
||||
|
||||
let layerStatus = 'off';
|
||||
|
||||
return linearRegressionCurveChartLayer;
|
||||
|
||||
function initialize(exchange, market, index, dailyFiles, botsPanel) {
|
||||
marketId = market;
|
||||
exchangeId = exchange;
|
||||
|
||||
marketIndex = index;
|
||||
dailyFilesCursor = dailyFiles;
|
||||
|
||||
recalculateScale();
|
||||
|
||||
layerStatus = botsPanel.getProductStatus(botsPanel.layerNames.LINEAR_REGRESION_CURVE);
|
||||
}
|
||||
|
||||
function getContainer(point) {
|
||||
var container;
|
||||
/* First we check if this point is inside this space. */
|
||||
if (this.container.frame.isThisPointHere(point) === true) {
|
||||
return this.container;
|
||||
} else {
|
||||
/* This point does not belong to this space. */
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function onLayerStatusChanged(eventData) {
|
||||
if (eventData.layer === 'Linear Regression Curve')
|
||||
layerStatus = eventData.status;
|
||||
}
|
||||
|
||||
function onCandlesChanged(newCandles) {
|
||||
candles = newCandles;
|
||||
recalculatePatterns();
|
||||
}
|
||||
|
||||
function setTimePeriod(period) {
|
||||
timePeriod = period;
|
||||
}
|
||||
|
||||
function setDatetime(newDatetime) {
|
||||
datetime = newDatetime;
|
||||
}
|
||||
|
||||
function draw() {
|
||||
if (layerStatus !== 'on') return;
|
||||
this.container.frame.draw();
|
||||
plotPatternChart(LRCArray15, 'rgba(182, 190, 255, 0.95)');
|
||||
plotPatternChart(LRCArray30, 'rgba(109, 125, 255, 0.95)');
|
||||
plotPatternChart(LRCArray60, 'rgba(57, 79, 255, 0.95)');
|
||||
}
|
||||
|
||||
function recalculatePatterns() {
|
||||
if (layerStatus === 'off') return;
|
||||
|
||||
LRCArray15 = calculateLRC(15); //TODO Maybe one single for statement will be more efficient to calculate the 3 LRC at once.
|
||||
LRCArray30 = calculateLRC(30);
|
||||
LRCArray60 = calculateLRC(60);
|
||||
}
|
||||
|
||||
function calculateLRC(depth){
|
||||
let LRCArray = [];
|
||||
let lrc15 = new LRCIndicator(depth);
|
||||
for (let i = 0; i < candles.length - 1; i++) {
|
||||
let currentCandle = candles[i];
|
||||
|
||||
let averagePrice = ( currentCandle.open + currentCandle.close ) / 2; // TODO Check which price should be take to get the LRC
|
||||
lrc15.update(averagePrice);
|
||||
|
||||
let yValue = averagePrice;
|
||||
if(lrc15.result != false) // TODO Check the history to get correct values on the calculation
|
||||
yValue = lrc15.result;
|
||||
|
||||
let lrcPoint = {
|
||||
x: currentCandle.begin,
|
||||
y: yValue
|
||||
};
|
||||
|
||||
LRCArray.push(lrcPoint);
|
||||
}
|
||||
return LRCArray;
|
||||
}
|
||||
|
||||
function plotPatternChart(LRCArray, color) {
|
||||
if (LRCArray.length > 0) {
|
||||
for (var i = 0; i < LRCArray.length; i++) {
|
||||
let currentLRCPoint = LRCArray[i];
|
||||
let nextLRCPoint = LRCArray[i+1];
|
||||
|
||||
if(nextLRCPoint === undefined) continue; // TODO Make sure this works well when there is data being received from the server
|
||||
|
||||
currentLRCPoint = plotArea.inverseTransform(currentLRCPoint, linearRegressionCurveChartLayer.container.frame.height);
|
||||
nextLRCPoint = plotArea.inverseTransform(nextLRCPoint, linearRegressionCurveChartLayer.container.frame.height);
|
||||
|
||||
currentLRCPoint = transformThisPoint(currentLRCPoint, linearRegressionCurveChartLayer.container);
|
||||
nextLRCPoint = transformThisPoint(nextLRCPoint, linearRegressionCurveChartLayer.container);
|
||||
|
||||
currentLRCPoint = viewPort.fitIntoVisibleArea(currentLRCPoint);
|
||||
nextLRCPoint = viewPort.fitIntoVisibleArea(nextLRCPoint);
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
browserCanvasContext.moveTo(currentLRCPoint.x, currentLRCPoint.y);
|
||||
browserCanvasContext.lineTo(nextLRCPoint.x, nextLRCPoint.y);
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
browserCanvasContext.strokeStyle = color;
|
||||
browserCanvasContext.fill();
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateScale() {
|
||||
var minValue = {
|
||||
x: EARLIEST_DATE.valueOf(),
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf(),
|
||||
y: nextPorwerOf10(marketIndex.maxRate())
|
||||
};
|
||||
|
||||
plotArea.initialize(
|
||||
minValue,
|
||||
maxValue,
|
||||
linearRegressionCurveChartLayer.container.frame.width,
|
||||
linearRegressionCurveChartLayer.container.frame.height
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,600 +0,0 @@
|
||||
|
||||
function newOrderBooksChartLayer() {
|
||||
|
||||
|
||||
var orderBooks = [];
|
||||
let timePeriod = INITIAL_TIME_PERIOD;
|
||||
|
||||
var plotArea = newPlotArea();
|
||||
|
||||
var datetime = INITIAL_DATE;
|
||||
|
||||
var orderBooksChartLayer = {
|
||||
onLayerStatusChanged: onLayerStatusChanged,
|
||||
setTimePeriod: setTimePeriod,
|
||||
setDatetime: setDatetime,
|
||||
container: undefined,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
var container = newContainer();
|
||||
container.initialize();
|
||||
orderBooksChartLayer.container = container;
|
||||
|
||||
container.displacement.containerName = "Order Books Chart Layer";
|
||||
container.zoom.containerName = "Order Books Chart Layer";
|
||||
container.frame.containerName = "Order Books Chart Layer";
|
||||
|
||||
let marketId;
|
||||
let exchangeId;
|
||||
let marketIndex;
|
||||
|
||||
let orderBookFilesCursor;
|
||||
|
||||
let amountScale;
|
||||
|
||||
let maxAmount = 0;
|
||||
|
||||
const TIME_FOR_RESOLUTION_CHANGE = 10;
|
||||
const MAX_RESOLUTION = 1;
|
||||
const MIN_RESOLUTION = 10;
|
||||
|
||||
let resolution = MIN_RESOLUTION;
|
||||
let timeWithoutZoomOrPane = 0;
|
||||
|
||||
const RECALCULATE_COUNTER_MAX_VALUE = 100;
|
||||
|
||||
let recalculateCounter = 0;
|
||||
|
||||
let layerStatus = 'off';
|
||||
|
||||
return orderBooksChartLayer;
|
||||
|
||||
|
||||
function initialize(exchange, market, index, botsPanel) {
|
||||
|
||||
marketId = market;
|
||||
exchangeId = exchange;
|
||||
marketIndex = index;
|
||||
|
||||
orderBookFilesCursor = newOrderBookFilesCursor();
|
||||
orderBookFilesCursor.initialize(exchangeId, marketId);
|
||||
|
||||
recalculateScale();
|
||||
|
||||
viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged);
|
||||
canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished);
|
||||
canvas.eventHandler.listenToEvent("Dragging", onDragging);
|
||||
|
||||
layerStatus = botsPanel.getProductStatus(botsPanel.layerNames.ORDER_BOOKS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getContainer(point) {
|
||||
|
||||
var container;
|
||||
|
||||
/* First we check if this point is inside this space. */
|
||||
|
||||
if (this.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return this.container;
|
||||
|
||||
} else {
|
||||
|
||||
/* This point does not belong to this space. */
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onLayerStatusChanged(eventData) {
|
||||
|
||||
if (eventData.layer === 'Order Books') {
|
||||
layerStatus = eventData.status;
|
||||
}
|
||||
|
||||
if (layerStatus !== 'on') { return; }
|
||||
|
||||
if (timePeriod <= _1_HOUR_IN_MILISECONDS) {
|
||||
|
||||
orderBookFilesCursor.setDatetime(datetime);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function onZoomChanged(event) {
|
||||
|
||||
if (timePeriod <= _1_HOUR_IN_MILISECONDS) {
|
||||
|
||||
timeWithoutZoomOrPane = 0;
|
||||
resolution++;
|
||||
|
||||
if (resolution > MIN_RESOLUTION) {
|
||||
resolution = MIN_RESOLUTION;
|
||||
}
|
||||
|
||||
recalculateCounter = recalculateCounter + RECALCULATE_COUNTER_MAX_VALUE / 10;
|
||||
|
||||
}
|
||||
|
||||
/* Defining when the file cursor is updated */
|
||||
|
||||
if (layerStatus === 'off') { return; }
|
||||
|
||||
if (timePeriod <= _1_HOUR_IN_MILISECONDS) {
|
||||
|
||||
orderBookFilesCursor.setDatetime(datetime);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function onDragFinished() {
|
||||
|
||||
if (timePeriod <= _1_HOUR_IN_MILISECONDS) {
|
||||
|
||||
recalculateOrderBooks();
|
||||
recalculateCounter = 0;
|
||||
|
||||
}
|
||||
|
||||
/* Defining when the file cursor is updated */
|
||||
|
||||
if (layerStatus === 'off') { return; }
|
||||
|
||||
if (timePeriod <= _1_HOUR_IN_MILISECONDS) {
|
||||
|
||||
orderBookFilesCursor.setDatetime(datetime);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function onDragging() {
|
||||
|
||||
recalculateCounter = 0;
|
||||
|
||||
}
|
||||
|
||||
function setTimePeriod(period) {
|
||||
|
||||
timePeriod = period;
|
||||
|
||||
}
|
||||
|
||||
function setDatetime(newDatetime) {
|
||||
datetime = newDatetime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
if (layerStatus !== 'on') { return; }
|
||||
|
||||
if (timePeriod <= _1_HOUR_IN_MILISECONDS) {
|
||||
|
||||
timeWithoutZoomOrPane++;
|
||||
|
||||
if (timeWithoutZoomOrPane > TIME_FOR_RESOLUTION_CHANGE) {
|
||||
resolution--;
|
||||
timeWithoutZoomOrPane = 0;
|
||||
if (resolution < MAX_RESOLUTION) {
|
||||
resolution = MAX_RESOLUTION;
|
||||
}
|
||||
|
||||
//recalculateOrderBooks();
|
||||
}
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
recalculateCounter++;
|
||||
|
||||
if (recalculateCounter > RECALCULATE_COUNTER_MAX_VALUE) {
|
||||
recalculateOrderBooks();
|
||||
recalculateCounter = 0;
|
||||
}
|
||||
|
||||
plotOrderBooksChart();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function recalculateOrderBooks() {
|
||||
|
||||
if (layerStatus === 'off') { return; }
|
||||
|
||||
/* get the bounderies */
|
||||
|
||||
let rateAtTop = getRateFromPoint(viewPort.visibleArea.topLeft, orderBooksChartLayer.container, plotArea);
|
||||
let rateAtBottom = getRateFromPoint(viewPort.visibleArea.bottomLeft, orderBooksChartLayer.container, plotArea);
|
||||
|
||||
let maxPossibleRate = rateAtTop + (rateAtTop - rateAtBottom);
|
||||
let minPossibleRate = rateAtBottom - (rateAtTop - rateAtBottom);
|
||||
|
||||
let timeAtLeft = getMilisecondsFromPoint(viewPort.visibleArea.topLeft, orderBooksChartLayer.container, plotArea);
|
||||
let timeAtRight = getMilisecondsFromPoint(viewPort.visibleArea.bottomRight, orderBooksChartLayer.container, plotArea);
|
||||
|
||||
let maxPossibleTime = timeAtRight + (timeAtRight - timeAtLeft);
|
||||
let minPossibleTime = timeAtLeft - (timeAtRight - timeAtLeft);
|
||||
|
||||
/* continue with the files */
|
||||
|
||||
let minutesOnSides = 1440 * 5;
|
||||
|
||||
let leftDateTime;
|
||||
let rightDateTime;
|
||||
|
||||
leftDateTime = new Date(datetime.getTime());
|
||||
|
||||
leftDateTime.setMinutes(leftDateTime.getMinutes() - minutesOnSides);
|
||||
|
||||
let absoluteLeft = Math.trunc(leftDateTime.valueOf() / timePeriod) * timePeriod;
|
||||
leftDateTime = new Date(absoluteLeft);
|
||||
|
||||
rightDateTime = new Date(leftDateTime.getTime());
|
||||
|
||||
rightDateTime.setMinutes(rightDateTime.getMinutes() + minutesOnSides * 2 );
|
||||
|
||||
let currentDate = new Date(leftDateTime.getTime());
|
||||
|
||||
orderBooks = [];
|
||||
|
||||
/* Lets calculate the current datetime with minutes precision */
|
||||
|
||||
let currentDatetime = new Date(datetime.getTime());
|
||||
|
||||
let currentMoment = Math.trunc(currentDatetime.valueOf() / _1_MINUTE_IN_MILISECONDS) * _1_MINUTE_IN_MILISECONDS;
|
||||
|
||||
|
||||
/* Lets calculate the precision */
|
||||
|
||||
let presicion = calculatePresicion(marketIndex.maxRate());
|
||||
|
||||
function calculatePresicion(number) {
|
||||
|
||||
for (let i = -10; i <= 10; i++) {
|
||||
if (number < Math.pow(10, i)) {
|
||||
return Math.pow(10, i - 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let orderBook = new Map();
|
||||
|
||||
const fileTimePeriod = 60 * 1000;
|
||||
const recordsPerCandle = timePeriod / fileTimePeriod * resolution;
|
||||
let currentRecord = 0;
|
||||
|
||||
while (currentDate.getTime() < rightDateTime.getTime()) {
|
||||
|
||||
currentRecord++;
|
||||
|
||||
let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2) + '-' + pad(currentDate.getHours(), 2) + '-' + pad(currentDate.getMinutes(), 2);
|
||||
|
||||
let orderBookFile = orderBookFilesCursor.orderBookFiles.get(stringDate);
|
||||
|
||||
if (orderBookFile !== undefined) {
|
||||
|
||||
if (orderBookFile.length > 0) {
|
||||
|
||||
let condensedMap;
|
||||
|
||||
condensedMap = condenceArray(orderBookFile[0], currentDate.valueOf());
|
||||
|
||||
for (let key of condensedMap.keys()) {
|
||||
|
||||
aggregate('ask', [key, condensedMap.get(key)]);
|
||||
|
||||
}
|
||||
|
||||
condensedMap = condenceArray(orderBookFile[1], currentDate.valueOf());
|
||||
|
||||
for (let key of condensedMap.keys()) {
|
||||
|
||||
aggregate('bid', [key, condensedMap.get(key)]);
|
||||
|
||||
}
|
||||
|
||||
function aggregate(type, fileRecord) {
|
||||
|
||||
let rate = fileRecord[0];
|
||||
|
||||
if (rate >= plotArea.max.y) { return; }
|
||||
if (rate <= plotArea.min.y) { return; }
|
||||
|
||||
let amount = fileRecord[1];
|
||||
|
||||
if (type === 'bid' && amount > maxAmount) { maxAmount = amount; }
|
||||
|
||||
let orderBookPosition = orderBook.get(type + rate) || newResistance();
|
||||
|
||||
if (orderBookPosition.type === undefined) {
|
||||
|
||||
orderBookPosition.type = type;
|
||||
orderBookPosition.rate = rate;
|
||||
|
||||
orderBookPosition.open = amount;
|
||||
orderBookPosition.close = amount;
|
||||
orderBookPosition.min = amount;
|
||||
orderBookPosition.max = amount;
|
||||
|
||||
orderBookPosition.begin = currentDate.valueOf();
|
||||
orderBookPosition.end = currentDate.valueOf() + fileTimePeriod;
|
||||
|
||||
} else {
|
||||
|
||||
if (amount < orderBookPosition.min) { orderBookPosition.min = amount; }
|
||||
if (amount > orderBookPosition.max) { orderBookPosition.max = amount; }
|
||||
|
||||
orderBookPosition.end = currentDate.valueOf() + fileTimePeriod;
|
||||
orderBookPosition.close = amount;
|
||||
|
||||
}
|
||||
|
||||
orderBook.set(type + rate, orderBookPosition);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentDate.setMinutes(currentDate.getMinutes() + 1);
|
||||
|
||||
if (currentRecord === recordsPerCandle) {
|
||||
|
||||
orderBooks.push(orderBook);
|
||||
|
||||
/* Lets see now if this order book is the one corresponding to the current moment in time */
|
||||
|
||||
let fisrtPosition = orderBook.values().next().value;
|
||||
|
||||
if (fisrtPosition !== undefined) {
|
||||
|
||||
if (currentMoment >= fisrtPosition.begin && currentMoment < fisrtPosition.end) {
|
||||
|
||||
orderBooksChartLayer.container.eventHandler.raiseEvent("Current Order Book Changed", orderBook);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Reset map and counter */
|
||||
|
||||
orderBook = new Map();
|
||||
|
||||
currentRecord = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the amount scale */
|
||||
|
||||
amountScale = presicion / maxAmount * 10;
|
||||
|
||||
function condenceArray(arrayToCondence, currentDatetime) {
|
||||
|
||||
let condencedMap = new Map();
|
||||
|
||||
let condenseFactor = getCondenseFactor(timePeriod);
|
||||
|
||||
for (var i = 0; i < arrayToCondence.length; i++) {
|
||||
|
||||
let fileRate = arrayToCondence[i][0];
|
||||
|
||||
let rate = Math.round(fileRate / presicion / condenseFactor) * presicion * condenseFactor;
|
||||
|
||||
let amount = arrayToCondence[i][1];
|
||||
|
||||
let storedAmount = condencedMap.get(rate) || 0;
|
||||
|
||||
amount = amount + storedAmount;
|
||||
|
||||
if (rate < maxPossibleRate && rate > minPossibleRate && currentDatetime > minPossibleTime && currentDatetime < maxPossibleTime ) {
|
||||
|
||||
condencedMap.set(rate, amount);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return condencedMap;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function recalculateScale() {
|
||||
|
||||
var minValue = {
|
||||
x: EARLIEST_DATE.valueOf(),
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf(),
|
||||
y: nextPorwerOf10(marketIndex.maxRate())
|
||||
};
|
||||
|
||||
plotArea.initialize(
|
||||
minValue,
|
||||
maxValue,
|
||||
orderBooksChartLayer.container.frame.width,
|
||||
orderBooksChartLayer.container.frame.height
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function plotOrderBooksChart() {
|
||||
|
||||
let transparencyLevel = getTransparenceFactor(timePeriod);
|
||||
|
||||
/* Now we calculate and plot the orderBooks */
|
||||
|
||||
for (let i = 0; i < orderBooks.length; i++) {
|
||||
|
||||
let orderBooksMap = orderBooks[i];
|
||||
|
||||
for (let key of orderBooksMap.keys()) {
|
||||
|
||||
let orderBookPosition = orderBooksMap.get(key);
|
||||
|
||||
let resistancePoint1 = {
|
||||
x: orderBookPosition.begin - (orderBookPosition.end - orderBookPosition.begin) * 2,
|
||||
y: orderBookPosition.rate
|
||||
};
|
||||
|
||||
let resistancePoint2 = {
|
||||
x: orderBookPosition.end + (orderBookPosition.end - orderBookPosition.begin) * 2,
|
||||
y: orderBookPosition.rate
|
||||
};
|
||||
|
||||
let resistancePoint3 = {
|
||||
x: orderBookPosition.end,
|
||||
y: orderBookPosition.rate + orderBookPosition.close * amountScale
|
||||
};
|
||||
|
||||
let resistancePoint4 = {
|
||||
x: orderBookPosition.begin,
|
||||
y: orderBookPosition.rate + orderBookPosition.open * amountScale
|
||||
};
|
||||
|
||||
let resistancePoint5 = {
|
||||
x: orderBookPosition.end,
|
||||
y: orderBookPosition.rate - orderBookPosition.close * amountScale
|
||||
};
|
||||
|
||||
let resistancePoint6 = {
|
||||
x: orderBookPosition.begin,
|
||||
y: orderBookPosition.rate - orderBookPosition.open * amountScale
|
||||
};
|
||||
|
||||
|
||||
resistancePoint1 = plotArea.inverseTransform(resistancePoint1, orderBooksChartLayer.container.frame.height);
|
||||
resistancePoint2 = plotArea.inverseTransform(resistancePoint2, orderBooksChartLayer.container.frame.height);
|
||||
resistancePoint3 = plotArea.inverseTransform(resistancePoint3, orderBooksChartLayer.container.frame.height);
|
||||
resistancePoint4 = plotArea.inverseTransform(resistancePoint4, orderBooksChartLayer.container.frame.height);
|
||||
resistancePoint5 = plotArea.inverseTransform(resistancePoint5, orderBooksChartLayer.container.frame.height);
|
||||
resistancePoint6 = plotArea.inverseTransform(resistancePoint6, orderBooksChartLayer.container.frame.height);
|
||||
|
||||
resistancePoint1 = transformThisPoint(resistancePoint1, orderBooksChartLayer.container);
|
||||
resistancePoint2 = transformThisPoint(resistancePoint2, orderBooksChartLayer.container);
|
||||
resistancePoint3 = transformThisPoint(resistancePoint3, orderBooksChartLayer.container);
|
||||
resistancePoint4 = transformThisPoint(resistancePoint4, orderBooksChartLayer.container);
|
||||
resistancePoint5 = transformThisPoint(resistancePoint5, orderBooksChartLayer.container);
|
||||
resistancePoint6 = transformThisPoint(resistancePoint6, orderBooksChartLayer.container);
|
||||
|
||||
if (resistancePoint2.x < viewPort.visibleArea.bottomLeft.x || resistancePoint1.x > viewPort.visibleArea.bottomRight.x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (resistancePoint6.y < viewPort.visibleArea.topLeft.y || resistancePoint4.y > viewPort.visibleArea.bottomRight.y) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
resistancePoint1 = viewPort.fitIntoVisibleArea(resistancePoint1);
|
||||
resistancePoint2 = viewPort.fitIntoVisibleArea(resistancePoint2);
|
||||
resistancePoint3 = viewPort.fitIntoVisibleArea(resistancePoint3);
|
||||
resistancePoint4 = viewPort.fitIntoVisibleArea(resistancePoint4);
|
||||
resistancePoint5 = viewPort.fitIntoVisibleArea(resistancePoint5);
|
||||
resistancePoint6 = viewPort.fitIntoVisibleArea(resistancePoint6);
|
||||
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(resistancePoint1.x, resistancePoint1.y);
|
||||
browserCanvasContext.lineTo(resistancePoint2.x, resistancePoint2.y);
|
||||
browserCanvasContext.lineTo(resistancePoint3.x, resistancePoint3.y);
|
||||
//browserCanvasContext.lineTo(resistancePoint6.x, resistancePoint6.y);
|
||||
browserCanvasContext.lineTo(resistancePoint4.x, resistancePoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (orderBookPosition.type === 'bid') {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(61, 135, 235, ' + transparencyLevel + ')';
|
||||
browserCanvasContext.strokeStyle = 'rgba(51, 112, 211, 0.20)';
|
||||
|
||||
}
|
||||
|
||||
if (orderBookPosition.type === 'ask') {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(60, 233, 252, ' + transparencyLevel + ')';
|
||||
browserCanvasContext.strokeStyle = 'rgba(8, 86, 94, ' + transparencyLevel + ')';
|
||||
|
||||
}
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= orderBookPosition.begin && dateValue < orderBookPosition.end) {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, ' + transparencyLevel + ')'; // Current orderBookPosition accroding to time
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
resistancePoint1.x < viewPort.visibleArea.topLeft.x + 50
|
||||
||
|
||||
resistancePoint1.x > viewPort.visibleArea.bottomRight.x - 50
|
||||
) {
|
||||
// we leave this orderBooks without fill.
|
||||
} else {
|
||||
browserCanvasContext.fill();
|
||||
}
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(resistancePoint1.x, resistancePoint1.y);
|
||||
browserCanvasContext.lineTo(resistancePoint2.x, resistancePoint2.y);
|
||||
browserCanvasContext.lineTo(resistancePoint5.x, resistancePoint5.y);
|
||||
browserCanvasContext.lineTo(resistancePoint6.x, resistancePoint6.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (
|
||||
resistancePoint1.x < viewPort.visibleArea.topLeft.x + 50
|
||||
||
|
||||
resistancePoint1.x > viewPort.visibleArea.bottomRight.x - 50
|
||||
) {
|
||||
// we leave this orderBooks without fill.
|
||||
} else {
|
||||
browserCanvasContext.fill();
|
||||
}
|
||||
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,337 +0,0 @@
|
||||
|
||||
function newSupportResistanceChartLayer() {
|
||||
|
||||
|
||||
var candles = [];
|
||||
let timePeriod = INITIAL_TIME_PERIOD;
|
||||
|
||||
var plotArea = newPlotArea();
|
||||
|
||||
var datetime = INITIAL_DATE;
|
||||
|
||||
var supportResistanceChartLayer = {
|
||||
onCandlesChanged: onCandlesChanged,
|
||||
setTimePeriod: setTimePeriod,
|
||||
setDatetime: setDatetime,
|
||||
container: undefined,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
var container = newContainer();
|
||||
container.initialize();
|
||||
supportResistanceChartLayer.container = container;
|
||||
|
||||
container.displacement.containerName = "Candle Stick Chart";
|
||||
container.zoom.containerName = "Candle Stick Chart";
|
||||
container.frame.containerName = "Candle Stick Chart";
|
||||
|
||||
let marketId;
|
||||
let exchangeId;
|
||||
|
||||
let marketIndex;
|
||||
let dailyFilesCursor;
|
||||
|
||||
let supportArray = [];
|
||||
|
||||
return supportResistanceChartLayer;
|
||||
|
||||
function initialize(exchange, market, index, dailyFiles, botsPanel) {
|
||||
|
||||
marketId = market;
|
||||
exchangeId = exchange;
|
||||
|
||||
marketIndex = index;
|
||||
dailyFilesCursor = dailyFiles;
|
||||
|
||||
recalculateScale();
|
||||
|
||||
layerStatus = botsPanel.getProductStatus(botsPanel.layerNames.CANDLESTICKS); // TODO : Put the right layer name here when it exists.
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getContainer(point) {
|
||||
|
||||
var container;
|
||||
|
||||
/* First we check if this point is inside this space. */
|
||||
|
||||
if (this.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return this.container;
|
||||
|
||||
} else {
|
||||
|
||||
/* This point does not belong to this space. */
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onCandlesChanged(newCandles) {
|
||||
|
||||
candles = newCandles;
|
||||
recalculateSupportResistance();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function setTimePeriod(period) {
|
||||
|
||||
timePeriod = period;
|
||||
|
||||
}
|
||||
|
||||
function setDatetime(newDatetime) {
|
||||
datetime = newDatetime;
|
||||
recalculateSupportResistance();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
plotSupportResistanceChart();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateSupportResistance() {
|
||||
|
||||
supportArray = [];
|
||||
let stairs;
|
||||
|
||||
for (let i = 0; i < candles.length - 1; i++) {
|
||||
|
||||
let currentCandle = candles[i];
|
||||
let nextCandle = candles[i + 1];
|
||||
|
||||
if (currentCandle.direction === nextCandle.direction && currentCandle.direction !== 'side') {
|
||||
|
||||
if (stairs === undefined) {
|
||||
|
||||
stairs = newCandleStairs();
|
||||
|
||||
stairs.direction = currentCandle.direction;
|
||||
stairs.candleCount = 2;
|
||||
|
||||
stairs.begin = currentCandle.begin;
|
||||
stairs.end = nextCandle.end;
|
||||
|
||||
stairs.open = currentCandle.open;
|
||||
stairs.close = nextCandle.close;
|
||||
|
||||
if (currentCandle.min < nextCandle.min) { stairs.min = currentCandle.min; } else { stairs.min = nextCandle.min }
|
||||
if (currentCandle.max > nextCandle.max) { stairs.max = currentCandle.max; } else { stairs.max = nextCandle.max }
|
||||
|
||||
if (stairs.direction === 'up') {
|
||||
|
||||
stairs.firstMin = currentCandle.open;
|
||||
stairs.firstMax = currentCandle.close;
|
||||
|
||||
stairs.lastMin = nextCandle.open;
|
||||
stairs.lastMax = nextCandle.close;
|
||||
|
||||
} else {
|
||||
|
||||
stairs.firstMin = currentCandle.close;
|
||||
stairs.firstMax = currentCandle.open;
|
||||
|
||||
stairs.lastMin = nextCandle.close;
|
||||
stairs.lastMax = nextCandle.open;
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
stairs.candleCount++;
|
||||
stairs.end = nextCandle.end;
|
||||
stairs.close = nextCandle.close;
|
||||
|
||||
if (stairs.min < nextCandle.min) { stairs.min = currentCandle.min; }
|
||||
if (stairs.max > nextCandle.max) { stairs.max = currentCandle.max; }
|
||||
|
||||
if (stairs.direction === 'up') {
|
||||
|
||||
stairs.lastMin = nextCandle.open;
|
||||
stairs.lastMax = nextCandle.close;
|
||||
|
||||
} else {
|
||||
|
||||
stairs.lastMin = nextCandle.close;
|
||||
stairs.lastMax = nextCandle.open;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (stairs !== undefined) {
|
||||
supportArray.push(stairs);
|
||||
stairs = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function recalculateScale() {
|
||||
|
||||
var minValue = {
|
||||
x: EARLIEST_DATE.valueOf(),
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf(),
|
||||
y: nextPorwerOf10(marketIndex.maxRate())
|
||||
};
|
||||
|
||||
|
||||
plotArea.initialize(
|
||||
minValue,
|
||||
maxValue,
|
||||
supportResistanceChartLayer.container.frame.width,
|
||||
supportResistanceChartLayer.container.frame.height
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function plotSupportResistanceChart() {
|
||||
|
||||
if (supportArray.length > 0) {
|
||||
|
||||
for (var i = 0; i < supportArray.length; i++) {
|
||||
|
||||
stairs = supportArray[i];
|
||||
|
||||
let stairsPoint1;
|
||||
let stairsPoint2;
|
||||
let stairsPoint3;
|
||||
let stairsPoint4;
|
||||
|
||||
if (stairs.direction === 'up') {
|
||||
|
||||
stairsPoint1 = {
|
||||
x: stairs.begin + timePeriod / 7 * 5.5,
|
||||
y: stairs.firstMin
|
||||
};
|
||||
|
||||
stairsPoint2 = {
|
||||
x: stairs.end - timePeriod / 7 * 1.5,
|
||||
y: stairs.lastMin
|
||||
};
|
||||
|
||||
stairsPoint3 = {
|
||||
x: stairs.end - timePeriod / 7 * 5.5,
|
||||
y: stairs.lastMax
|
||||
};
|
||||
|
||||
stairsPoint4 = {
|
||||
x: stairs.begin + timePeriod / 7 * 1.5,
|
||||
y: stairs.firstMax
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
stairsPoint1 = {
|
||||
x: stairs.begin + timePeriod / 7 * 1.5,
|
||||
y: stairs.firstMin
|
||||
};
|
||||
|
||||
stairsPoint2 = {
|
||||
x: stairs.end - timePeriod / 7 * 5.5,
|
||||
y: stairs.lastMin
|
||||
};
|
||||
|
||||
stairsPoint3 = {
|
||||
x: stairs.end - timePeriod / 7 * 1.5,
|
||||
y: stairs.lastMax
|
||||
};
|
||||
|
||||
stairsPoint4 = {
|
||||
x: stairs.begin + timePeriod / 7 * 5.5,
|
||||
y: stairs.firstMax
|
||||
};
|
||||
}
|
||||
|
||||
stairsPoint1 = plotArea.inverseTransform(stairsPoint1, supportResistanceChartLayer.container.frame.height);
|
||||
stairsPoint2 = plotArea.inverseTransform(stairsPoint2, supportResistanceChartLayer.container.frame.height);
|
||||
stairsPoint3 = plotArea.inverseTransform(stairsPoint3, supportResistanceChartLayer.container.frame.height);
|
||||
stairsPoint4 = plotArea.inverseTransform(stairsPoint4, supportResistanceChartLayer.container.frame.height);
|
||||
|
||||
stairsPoint1 = transformThisPoint(stairsPoint1, supportResistanceChartLayer.container);
|
||||
stairsPoint2 = transformThisPoint(stairsPoint2, supportResistanceChartLayer.container);
|
||||
stairsPoint3 = transformThisPoint(stairsPoint3, supportResistanceChartLayer.container);
|
||||
stairsPoint4 = transformThisPoint(stairsPoint4, supportResistanceChartLayer.container);
|
||||
|
||||
if (stairsPoint2.x < viewPort.visibleArea.bottomLeft.x || stairsPoint1.x > viewPort.visibleArea.bottomRight.x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stairsPoint1 = viewPort.fitIntoVisibleArea(stairsPoint1);
|
||||
stairsPoint2 = viewPort.fitIntoVisibleArea(stairsPoint2);
|
||||
stairsPoint3 = viewPort.fitIntoVisibleArea(stairsPoint3);
|
||||
stairsPoint4 = viewPort.fitIntoVisibleArea(stairsPoint4);
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(stairsPoint1.x, stairsPoint1.y);
|
||||
browserCanvasContext.lineTo(stairsPoint2.x, stairsPoint2.y);
|
||||
browserCanvasContext.lineTo(stairsPoint3.x, stairsPoint3.y);
|
||||
browserCanvasContext.lineTo(stairsPoint4.x, stairsPoint4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
let opacity = '0.25';
|
||||
|
||||
if (stairs.direction === 'up') { browserCanvasContext.strokeStyle = 'rgba(27, 105, 7, ' + opacity + ')'; }
|
||||
if (stairs.direction === 'down') { browserCanvasContext.strokeStyle = 'rgba(130, 9, 9, ' + opacity + ')'; }
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= stairs.begin && dateValue <= stairs.end) {
|
||||
|
||||
|
||||
/* highlight the current stairs */
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, 0.1)'; // Current stairs accroding to time
|
||||
|
||||
} else {
|
||||
|
||||
if (stairs.direction === 'up') { browserCanvasContext.fillStyle = 'rgba(64, 217, 26, ' + opacity + ')'; }
|
||||
if (stairs.direction === 'down') { browserCanvasContext.fillStyle = 'rgba(219, 18, 18, ' + opacity + ')'; }
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (stairs.direction === 'up') { browserCanvasContext.fillStyle = 'rgba(64, 217, 26, ' + opacity + ')'; }
|
||||
if (stairs.direction === 'down') { browserCanvasContext.fillStyle = 'rgba(219, 18, 18, ' + opacity + ')'; }
|
||||
}
|
||||
|
||||
browserCanvasContext.fill();
|
||||
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,609 +0,0 @@
|
||||
|
||||
function newVolumeChartLayer() {
|
||||
|
||||
|
||||
var volumeBars = [];
|
||||
let timePeriod = INITIAL_TIME_PERIOD;
|
||||
|
||||
var plotArea = newPlotArea();
|
||||
var plotAreaFrame = newPlotArea();
|
||||
|
||||
let datetime = INITIAL_DATE;
|
||||
|
||||
var volumeChartLayer = {
|
||||
onLayerStatusChanged: onLayerStatusChanged,
|
||||
setTimePeriod: setTimePeriod,
|
||||
setDatetime: setDatetime,
|
||||
container: undefined,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
var container = newContainer();
|
||||
container.initialize();
|
||||
volumeChartLayer.container = container;
|
||||
|
||||
container.displacement.containerName = "VolumeBar Stick Chart";
|
||||
container.zoom.containerName = "VolumeBar Stick Chart";
|
||||
container.frame.containerName = "VolumeBar Stick Chart";
|
||||
|
||||
var marketId;
|
||||
var exchangeId;
|
||||
|
||||
let marketIndex;
|
||||
let dailyFilesCursor;
|
||||
|
||||
let maxAccumulatedBalance = 0;
|
||||
const MAX_ACCUMULATED_BALANCE_BARS_HEIGHT = 150;
|
||||
|
||||
let layerStatus = 'off';
|
||||
|
||||
return volumeChartLayer;
|
||||
|
||||
function initialize(exchange, market, index, dailyFiles, botsPanel) {
|
||||
|
||||
marketId = market;
|
||||
exchangeId = exchange;
|
||||
|
||||
marketIndex = index;
|
||||
dailyFilesCursor = dailyFiles;
|
||||
|
||||
recalculateScaleX();
|
||||
recalculateVolumeBars();
|
||||
recalculateScaleY();
|
||||
|
||||
viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged);
|
||||
canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished);
|
||||
|
||||
layerStatus = botsPanel.getProductStatus(botsPanel.layerNames.VOLUME);
|
||||
|
||||
}
|
||||
|
||||
function getContainer(point) {
|
||||
|
||||
var container;
|
||||
|
||||
/* First we check if this point is inside this space. */
|
||||
|
||||
if (this.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return this.container;
|
||||
|
||||
} else {
|
||||
|
||||
/* This point does not belong to this space. */
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onLayerStatusChanged(eventData) {
|
||||
|
||||
if (eventData.layer === 'Volume') {
|
||||
layerStatus = eventData.status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onZoomChanged(event) {
|
||||
|
||||
recalculateScaleX();
|
||||
recalculateVolumeBars();
|
||||
recalculateScaleY();
|
||||
|
||||
}
|
||||
|
||||
function onDragFinished() {
|
||||
|
||||
if (timePeriod !== ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
recalculateScaleX();
|
||||
recalculateVolumeBars();
|
||||
recalculateScaleY();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function setTimePeriod(period) {
|
||||
|
||||
timePeriod = period;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function setDatetime(newDatetime) {
|
||||
datetime = newDatetime;
|
||||
recalculateVolumeBars();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
if (layerStatus !== 'on') { return; }
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
if (timePeriod !== ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
if (Math.random() * 100 > 98) {
|
||||
recalculateScaleX();
|
||||
recalculateVolumeBars();
|
||||
recalculateScaleY();
|
||||
}
|
||||
}
|
||||
|
||||
plotVolumeBarChart();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateVolumeBars() {
|
||||
|
||||
if (layerStatus === 'off') { return; }
|
||||
|
||||
if (timePeriod === ONE_DAY_IN_MILISECONDS) {
|
||||
|
||||
recalculateVolumeBarsUsingMarketIndex();
|
||||
|
||||
} else {
|
||||
|
||||
recalculateVolumeBarsUsingDailyFiles();
|
||||
|
||||
}
|
||||
|
||||
volumeChartLayer.container.eventHandler.raiseEvent("Volumes Changed", volumeBars);
|
||||
}
|
||||
|
||||
function recalculateVolumeBarsUsingMarketIndex() {
|
||||
|
||||
volumeBars = [];
|
||||
|
||||
let accumulatedBuys = 0;
|
||||
let accumulatedSells = 0;
|
||||
maxAccumulatedBalance = 0;
|
||||
|
||||
for (var i = 0; i < marketIndex.volumes.length; i++) {
|
||||
|
||||
var volumeBar = newVolumeBar();
|
||||
|
||||
volumeBar.begin = (new Date(marketIndex.volumes[i][2])).valueOf();
|
||||
volumeBar.end = (new Date(marketIndex.volumes[i][3])).valueOf();
|
||||
|
||||
volumeBar.amountBuy = marketIndex.volumes[i][0];
|
||||
volumeBar.amountSell = marketIndex.volumes[i][1];
|
||||
|
||||
accumulatedBuys = accumulatedBuys + volumeBar.amountBuy;
|
||||
accumulatedSells = accumulatedSells + volumeBar.amountSell;
|
||||
|
||||
volumeBars.push(volumeBar);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateVolumeBarsUsingDailyFiles(currentDateOnly) {
|
||||
|
||||
let daysOnSides = getSideDays(timePeriod);
|
||||
|
||||
let leftDate;
|
||||
let rightDate;
|
||||
|
||||
if (currentDateOnly === true) {
|
||||
|
||||
leftDate = new Date(datetime.getTime());
|
||||
rightDate = new Date(datetime.getTime());
|
||||
|
||||
leftDate = removeTime(datetime);
|
||||
rightDate = removeTime(datetime);
|
||||
|
||||
} else {
|
||||
|
||||
leftDate = getDateFromPoint(viewPort.visibleArea.topLeft, volumeChartLayer.container, plotArea);
|
||||
rightDate = getDateFromPoint(viewPort.visibleArea.topRight, volumeChartLayer.container, plotArea);
|
||||
|
||||
leftDate.setDate(leftDate.getDate() - daysOnSides);
|
||||
rightDate.setDate(rightDate.getDate() + daysOnSides);
|
||||
|
||||
}
|
||||
|
||||
let currentDate = new Date(leftDate.getTime());
|
||||
|
||||
volumeBars = [];
|
||||
|
||||
while (currentDate.getTime() <= rightDate.getTime()) {
|
||||
|
||||
let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2);
|
||||
|
||||
let dailyFile = dailyFilesCursor.dailyFiles.get(stringDate);
|
||||
|
||||
if (dailyFile !== undefined) {
|
||||
|
||||
const fileTimePeriod = 60 * 1000;
|
||||
const totalVolumeBars = dailyFile.length * fileTimePeriod / timePeriod;
|
||||
const recordsPerVolumeBar = timePeriod / fileTimePeriod;
|
||||
|
||||
for (var i = 0; i < totalVolumeBars; i++) {
|
||||
|
||||
var volumeBar = newVolumeBar();
|
||||
|
||||
for (var j = 0; j < recordsPerVolumeBar; j++) {
|
||||
|
||||
volumeBar.amountBuy = volumeBar.amountBuy + dailyFile[i * recordsPerVolumeBar + j][8];
|
||||
volumeBar.amountSell = volumeBar.amountSell + dailyFile[i * recordsPerVolumeBar + j][9];
|
||||
|
||||
}
|
||||
|
||||
volumeBar.begin = dailyFile[i * recordsPerVolumeBar][4];
|
||||
volumeBar.end = dailyFile[i * recordsPerVolumeBar + recordsPerVolumeBar - 1][5];
|
||||
|
||||
volumeBars.push(volumeBar);
|
||||
}
|
||||
|
||||
}
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateScaleX() {
|
||||
|
||||
|
||||
var minValue = {
|
||||
x: EARLIEST_DATE.valueOf()
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf()
|
||||
};
|
||||
|
||||
plotArea.initializeX(
|
||||
minValue,
|
||||
maxValue,
|
||||
volumeChartLayer.container.frame.width
|
||||
);
|
||||
|
||||
plotAreaFrame.initializeX(
|
||||
minValue,
|
||||
maxValue,
|
||||
volumeChartLayer.container.frame.width
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateScaleY() {
|
||||
|
||||
var minValue = {
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
y: 0
|
||||
};
|
||||
|
||||
let timePeriodRatio = ONE_DAY_IN_MILISECONDS / timePeriod;
|
||||
|
||||
maxValue.y = marketIndex.maxVolume() / (timePeriodRatio / 10);
|
||||
|
||||
plotArea.initializeY(
|
||||
minValue,
|
||||
maxValue,
|
||||
viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topLeft.y
|
||||
);
|
||||
|
||||
plotAreaFrame.initializeY(
|
||||
minValue,
|
||||
maxValue,
|
||||
volumeChartLayer.container.frame.height
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function plotVolumeBarChart() {
|
||||
|
||||
let visibleHeight = viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topLeft.y;
|
||||
|
||||
let frameCorner1 = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
|
||||
let frameCorner2 = {
|
||||
x: volumeChartLayer.container.frame.width,
|
||||
y: volumeChartLayer.container.frame.height
|
||||
};
|
||||
|
||||
|
||||
/* Now the transformations. */
|
||||
|
||||
frameCorner1 = transformThisPoint(frameCorner1, volumeChartLayer.container.frame.container);
|
||||
frameCorner2 = transformThisPoint(frameCorner2, volumeChartLayer.container.frame.container);
|
||||
|
||||
let frameHeightInViewPort = frameCorner2.y - frameCorner1.y;
|
||||
|
||||
if (volumeBars.length > 0) {
|
||||
|
||||
for (var i = 0; i < volumeBars.length; i++) {
|
||||
|
||||
volumeBar = volumeBars[i];
|
||||
|
||||
let volumeBarPointA1;
|
||||
let volumeBarPointA2;
|
||||
let volumeBarPointA3;
|
||||
let volumeBarPointA4;
|
||||
|
||||
function calculateBuys(plot, height) {
|
||||
|
||||
volumeBarPointA1 = {
|
||||
x: volumeBar.begin + timePeriod / 7 * 2,
|
||||
y: 0
|
||||
};
|
||||
|
||||
volumeBarPointA2 = {
|
||||
x: volumeBar.begin + timePeriod / 7 * 2,
|
||||
y: volumeBar.amountBuy
|
||||
};
|
||||
|
||||
volumeBarPointA3 = {
|
||||
x: volumeBar.begin + timePeriod / 7 * 5,
|
||||
y: volumeBar.amountBuy
|
||||
};
|
||||
|
||||
volumeBarPointA4 = {
|
||||
x: volumeBar.begin + timePeriod / 7 * 5,
|
||||
y: 0
|
||||
};
|
||||
|
||||
volumeBarPointA1 = plot.inverseTransform(volumeBarPointA1, height);
|
||||
volumeBarPointA2 = plot.inverseTransform(volumeBarPointA2, height);
|
||||
volumeBarPointA3 = plot.inverseTransform(volumeBarPointA3, height);
|
||||
volumeBarPointA4 = plot.inverseTransform(volumeBarPointA4, height);
|
||||
|
||||
volumeBarPointA1 = transformThisPoint(volumeBarPointA1, volumeChartLayer.container);
|
||||
volumeBarPointA2 = transformThisPoint(volumeBarPointA2, volumeChartLayer.container);
|
||||
volumeBarPointA3 = transformThisPoint(volumeBarPointA3, volumeChartLayer.container);
|
||||
volumeBarPointA4 = transformThisPoint(volumeBarPointA4, volumeChartLayer.container);
|
||||
|
||||
let baseIncrement = (volumeBarPointA3.x - volumeBarPointA1.x) * WIDHTER_VOLUME_BAR_BASE_FACTOR;
|
||||
|
||||
volumeBarPointA1.x = volumeBarPointA1.x - baseIncrement;
|
||||
volumeBarPointA4.x = volumeBarPointA4.x + baseIncrement;
|
||||
|
||||
if (volumeBarPointA4.x < viewPort.visibleArea.bottomLeft.x || volumeBarPointA1.x > viewPort.visibleArea.bottomRight.x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
if (calculateBuys(plotAreaFrame, volumeChartLayer.container.frame.height) === false) { continue; } // We try to see if it fits in the visible area.
|
||||
|
||||
if (volumeBarPointA1.y > viewPort.visibleArea.bottomLeft.y && frameHeightInViewPort > visibleHeight * 2 / 3) {
|
||||
|
||||
if (calculateBuys(plotArea, visibleHeight) === false) { continue; } // We snap t to the view port.
|
||||
|
||||
/* Now we set the real value of y. */
|
||||
|
||||
volumeBarPointA1.y = viewPort.visibleArea.bottomRight.y;
|
||||
volumeBarPointA2.y = viewPort.visibleArea.bottomRight.y - volumeBar.amountBuy * plotArea.scale.y;
|
||||
volumeBarPointA3.y = viewPort.visibleArea.bottomRight.y - volumeBar.amountBuy * plotArea.scale.y;
|
||||
volumeBarPointA4.y = viewPort.visibleArea.bottomRight.y;
|
||||
|
||||
}
|
||||
|
||||
let volumeBarPointB1;
|
||||
let volumeBarPointB2;
|
||||
let volumeBarPointB3;
|
||||
let volumeBarPointB4;
|
||||
|
||||
function calculateSells(plot, height) {
|
||||
|
||||
volumeBarPointB1 = {
|
||||
x: volumeBar.begin + timePeriod / 7 * 2,
|
||||
y: height
|
||||
};
|
||||
|
||||
volumeBarPointB2 = {
|
||||
x: volumeBar.begin + timePeriod / 7 * 2,
|
||||
y: height - volumeBar.amountSell
|
||||
};
|
||||
|
||||
volumeBarPointB3 = {
|
||||
x: volumeBar.begin + timePeriod / 7 * 5,
|
||||
y: height - volumeBar.amountSell
|
||||
};
|
||||
|
||||
volumeBarPointB4 = {
|
||||
x: volumeBar.begin + timePeriod / 7 * 5,
|
||||
y: height
|
||||
};
|
||||
|
||||
volumeBarPointB1 = plot.inverseTransform2(volumeBarPointB1, height);
|
||||
volumeBarPointB2 = plot.inverseTransform2(volumeBarPointB2, height);
|
||||
volumeBarPointB3 = plot.inverseTransform2(volumeBarPointB3, height);
|
||||
volumeBarPointB4 = plot.inverseTransform2(volumeBarPointB4, height);
|
||||
|
||||
volumeBarPointB1 = transformThisPoint(volumeBarPointB1, volumeChartLayer.container);
|
||||
volumeBarPointB2 = transformThisPoint(volumeBarPointB2, volumeChartLayer.container);
|
||||
volumeBarPointB3 = transformThisPoint(volumeBarPointB3, volumeChartLayer.container);
|
||||
volumeBarPointB4 = transformThisPoint(volumeBarPointB4, volumeChartLayer.container);
|
||||
|
||||
}
|
||||
|
||||
calculateSells(plotAreaFrame, volumeChartLayer.container.frame.height); // We try to see if it fits in the visible area.
|
||||
|
||||
if (volumeBarPointB1.y < viewPort.visibleArea.topLeft.y && frameHeightInViewPort > visibleHeight * 2 / 3) {
|
||||
|
||||
calculateSells(plotArea, visibleHeight); // We snap it to the view port.
|
||||
|
||||
/* Now we set the real value of y. */
|
||||
|
||||
volumeBarPointB1.y = viewPort.visibleArea.topLeft.y;
|
||||
volumeBarPointB2.y = viewPort.visibleArea.topLeft.y + volumeBar.amountSell * plotArea.scale.y;
|
||||
volumeBarPointB3.y = viewPort.visibleArea.topLeft.y + volumeBar.amountSell * plotArea.scale.y;
|
||||
volumeBarPointB4.y = viewPort.visibleArea.topLeft.y;
|
||||
|
||||
}
|
||||
|
||||
/* We put a wider base */
|
||||
|
||||
let baseIncrement = (volumeBarPointB3.x - volumeBarPointB1.x) * WIDHTER_VOLUME_BAR_BASE_FACTOR;
|
||||
|
||||
volumeBarPointB1.x = volumeBarPointB1.x - baseIncrement;
|
||||
volumeBarPointB4.x = volumeBarPointB4.x + baseIncrement;
|
||||
|
||||
/* We put a less wider top */
|
||||
|
||||
let baseDencrement = (volumeBarPointA3.x - volumeBarPointA2.x) * LESS_WIDHTER_VOLUME_BAR_TOP_FACTOR;
|
||||
|
||||
volumeBarPointA2.x = volumeBarPointA2.x + baseDencrement;
|
||||
volumeBarPointA3.x = volumeBarPointA3.x - baseDencrement;
|
||||
|
||||
volumeBarPointB2.x = volumeBarPointB2.x + baseDencrement;
|
||||
volumeBarPointB3.x = volumeBarPointB3.x - baseDencrement;
|
||||
|
||||
|
||||
/* Everything must fit within the visible area */
|
||||
|
||||
volumeBarPointA1 = viewPort.fitIntoVisibleArea(volumeBarPointA1);
|
||||
volumeBarPointA2 = viewPort.fitIntoVisibleArea(volumeBarPointA2);
|
||||
volumeBarPointA3 = viewPort.fitIntoVisibleArea(volumeBarPointA3);
|
||||
volumeBarPointA4 = viewPort.fitIntoVisibleArea(volumeBarPointA4);
|
||||
|
||||
volumeBarPointB1 = viewPort.fitIntoVisibleArea(volumeBarPointB1);
|
||||
volumeBarPointB2 = viewPort.fitIntoVisibleArea(volumeBarPointB2);
|
||||
volumeBarPointB3 = viewPort.fitIntoVisibleArea(volumeBarPointB3);
|
||||
volumeBarPointB4 = viewPort.fitIntoVisibleArea(volumeBarPointB4);
|
||||
|
||||
/* 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 (volumeBarPointA2.y < volumeBarPointB1.y) {
|
||||
|
||||
volumeBarPointA2.y = volumeBarPointB1.y;
|
||||
volumeBarPointA3.y = volumeBarPointB1.y;
|
||||
|
||||
}
|
||||
|
||||
if (volumeBarPointB2.y > volumeBarPointA1.y) {
|
||||
|
||||
volumeBarPointB2.y = volumeBarPointA1.y;
|
||||
volumeBarPointB3.y = volumeBarPointA1.y;
|
||||
|
||||
}
|
||||
|
||||
/* Now the drawing of the volume bars*/
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(volumeBarPointA1.x, volumeBarPointA1.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointA2.x, volumeBarPointA2.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointA3.x, volumeBarPointA3.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointA4.x, volumeBarPointA4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= volumeBar.begin && dateValue <= volumeBar.end) {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, 0.40)'; // Current bar accroding to time
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(64, 217, 26, 0.40)';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(64, 217, 26, 0.40)';
|
||||
|
||||
}
|
||||
|
||||
browserCanvasContext.fill();
|
||||
browserCanvasContext.strokeStyle = 'rgba(27, 105, 7, 0.40)';
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(volumeBarPointB1.x, volumeBarPointB1.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointB2.x, volumeBarPointB2.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointB3.x, volumeBarPointB3.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointB4.x, volumeBarPointB4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= volumeBar.begin && dateValue <= volumeBar.end) {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, 0.40)'; // Current candle accroding to time
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(219, 18, 18, 0.40)';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(219, 18, 18, 0.40)';
|
||||
|
||||
}
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(130, 9, 9, 0.40)';
|
||||
|
||||
browserCanvasContext.fill();
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= volumeBar.begin && dateValue <= volumeBar.end) {
|
||||
|
||||
let buyInfo = {
|
||||
baseWidth: volumeBarPointA4.x - volumeBarPointA1.x,
|
||||
topWidth: volumeBarPointA3.x - volumeBarPointA2.x,
|
||||
height: volumeBarPointA2.y - volumeBarPointA1.y
|
||||
};
|
||||
|
||||
let sellInfo = {
|
||||
baseWidth: volumeBarPointB4.x - volumeBarPointB1.x,
|
||||
topWidth: volumeBarPointB3.x - volumeBarPointB2.x,
|
||||
height: volumeBarPointB2.y - volumeBarPointB1.y
|
||||
};
|
||||
|
||||
let currentVolume = {
|
||||
buyInfo: buyInfo,
|
||||
sellInfo: sellInfo,
|
||||
period: timePeriod,
|
||||
innerVolumeBar: volumeBar
|
||||
};
|
||||
|
||||
volumeChartLayer.container.eventHandler.raiseEvent("Current Volume Info Changed", currentVolume);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,628 +0,0 @@
|
||||
|
||||
function newVolumeTechnicalAnalisysChartLayer() {
|
||||
|
||||
|
||||
var volumes = [];
|
||||
let timePeriod = INITIAL_TIME_PERIOD;
|
||||
|
||||
var plotArea = newPlotArea();
|
||||
var plotAreaFrame = newPlotArea();
|
||||
|
||||
var datetime = INITIAL_DATE;
|
||||
|
||||
var volumeTechnicalAnalisysChartLayer = {
|
||||
onLayerStatusChanged: onLayerStatusChanged,
|
||||
onVolumesChanged: onVolumesChanged,
|
||||
setTimePeriod: setTimePeriod,
|
||||
setDatetime: setDatetime,
|
||||
container: undefined,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize
|
||||
};
|
||||
|
||||
var container = newContainer();
|
||||
container.initialize();
|
||||
volumeTechnicalAnalisysChartLayer.container = container;
|
||||
|
||||
container.displacement.containerName = "Volume Technical Analisys Chart";
|
||||
container.zoom.containerName = "Volume Technical Analisys Chart";
|
||||
container.frame.containerName = "Volume Technical Analisys Chart";
|
||||
|
||||
let marketId;
|
||||
let exchangeId;
|
||||
|
||||
let marketIndex;
|
||||
let dailyFilesCursor;
|
||||
|
||||
let stairsArray = [];
|
||||
|
||||
let layerStatus = 'off';
|
||||
let parentLayerStatus = 'off';
|
||||
|
||||
return volumeTechnicalAnalisysChartLayer;
|
||||
|
||||
function initialize(exchange, market, index, dailyFiles, botsPanel) {
|
||||
|
||||
marketId = market;
|
||||
exchangeId = exchange;
|
||||
|
||||
marketIndex = index;
|
||||
dailyFilesCursor = dailyFiles;
|
||||
|
||||
layerStatus = botsPanel.getProductStatus(botsPanel.layerNames.VOLUME_STAIRS);
|
||||
parentLayerStatus = botsPanel.getProductStatus(botsPanel.layerNames.VOLUME);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getContainer(point) {
|
||||
|
||||
var container;
|
||||
|
||||
/* First we check if this point is inside this space. */
|
||||
|
||||
if (this.container.frame.isThisPointHere(point) === true) {
|
||||
|
||||
return this.container;
|
||||
|
||||
} else {
|
||||
|
||||
/* This point does not belong to this space. */
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onLayerStatusChanged(eventData) {
|
||||
|
||||
if (eventData.layer === 'Volume') {
|
||||
parentLayerStatus = eventData.status;
|
||||
}
|
||||
|
||||
if (eventData.layer === 'Volume Stairs') {
|
||||
layerStatus = eventData.status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function onVolumesChanged(newVolumes) {
|
||||
|
||||
volumes = newVolumes;
|
||||
|
||||
recalculateScaleX();
|
||||
recalculatePatterns();
|
||||
recalculateScaleY();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function setTimePeriod(period) {
|
||||
|
||||
timePeriod = period;
|
||||
|
||||
}
|
||||
|
||||
function setDatetime(newDatetime) {
|
||||
datetime = newDatetime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
if (layerStatus !== 'on') { return; }
|
||||
|
||||
if (parentLayerStatus === 'off') { return; }
|
||||
|
||||
this.container.frame.draw();
|
||||
|
||||
plotPatternChart();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculatePatterns() {
|
||||
|
||||
if (layerStatus === 'off') { return; }
|
||||
|
||||
if (parentLayerStatus === 'off') { return; }
|
||||
|
||||
/* Finding stairs */
|
||||
stairsArray = [];
|
||||
|
||||
let buyUpStairs;
|
||||
let buyDownStairs;
|
||||
|
||||
let sellUpStairs;
|
||||
let sellDownStairs;
|
||||
|
||||
for (let i = 0; i < volumes.length - 1; i++) {
|
||||
|
||||
let currentVolume = volumes[i];
|
||||
let nextVolume = volumes[i + 1];
|
||||
|
||||
|
||||
/* buy volume going up */
|
||||
|
||||
if (currentVolume.amountBuy < nextVolume.amountBuy) {
|
||||
|
||||
if (buyUpStairs === undefined) {
|
||||
|
||||
buyUpStairs = newVolumeStairs();
|
||||
|
||||
buyUpStairs.type = 'buy';
|
||||
buyUpStairs.direction = 'up';
|
||||
buyUpStairs.barsCount = 2;
|
||||
|
||||
buyUpStairs.begin = currentVolume.begin;
|
||||
buyUpStairs.end = nextVolume.end;
|
||||
|
||||
buyUpStairs.firstAmount = currentVolume.amountBuy;
|
||||
buyUpStairs.lastAmount = nextVolume.amountBuy;
|
||||
|
||||
} else {
|
||||
|
||||
buyUpStairs.barsCount++;
|
||||
buyUpStairs.end = nextVolume.end;
|
||||
buyUpStairs.lastAmount = nextVolume.amountBuy;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (buyUpStairs !== undefined) {
|
||||
|
||||
if (buyUpStairs.barsCount > 2) {
|
||||
|
||||
stairsArray.push(buyUpStairs);
|
||||
}
|
||||
|
||||
buyUpStairs = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/* buy volume going down */
|
||||
|
||||
if (currentVolume.amountBuy > nextVolume.amountBuy) {
|
||||
|
||||
if (buyDownStairs === undefined) {
|
||||
|
||||
buyDownStairs = newVolumeStairs();
|
||||
|
||||
buyDownStairs.type = 'buy';
|
||||
buyDownStairs.direction = 'down';
|
||||
buyDownStairs.barsCount = 2;
|
||||
|
||||
buyDownStairs.begin = currentVolume.begin;
|
||||
buyDownStairs.end = nextVolume.end;
|
||||
|
||||
buyDownStairs.firstAmount = currentVolume.amountBuy;
|
||||
buyDownStairs.lastAmount = nextVolume.amountBuy;
|
||||
|
||||
} else {
|
||||
|
||||
buyDownStairs.barsCount++;
|
||||
buyDownStairs.end = nextVolume.end;
|
||||
buyDownStairs.lastAmount = nextVolume.amountBuy;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (buyDownStairs !== undefined) {
|
||||
|
||||
if (buyDownStairs.barsCount > 2) {
|
||||
|
||||
stairsArray.push(buyDownStairs);
|
||||
}
|
||||
|
||||
buyDownStairs = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/* sell volume going up */
|
||||
|
||||
if (currentVolume.amountSell < nextVolume.amountSell) {
|
||||
|
||||
if (sellUpStairs === undefined) {
|
||||
|
||||
sellUpStairs = newVolumeStairs();
|
||||
|
||||
sellUpStairs.type = 'sell';
|
||||
sellUpStairs.direction = 'up';
|
||||
sellUpStairs.barsCount = 2;
|
||||
|
||||
sellUpStairs.begin = currentVolume.begin;
|
||||
sellUpStairs.end = nextVolume.end;
|
||||
|
||||
sellUpStairs.firstAmount = currentVolume.amountSell;
|
||||
sellUpStairs.lastAmount = nextVolume.amountSell;
|
||||
|
||||
} else {
|
||||
|
||||
sellUpStairs.barsCount++;
|
||||
sellUpStairs.end = nextVolume.end;
|
||||
sellUpStairs.lastAmount = nextVolume.amountSell;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (sellUpStairs !== undefined) {
|
||||
|
||||
if (sellUpStairs.barsCount > 2) {
|
||||
|
||||
stairsArray.push(sellUpStairs);
|
||||
}
|
||||
|
||||
sellUpStairs = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/* sell volume going down */
|
||||
|
||||
if (currentVolume.amountSell > nextVolume.amountSell) {
|
||||
|
||||
if (sellDownStairs === undefined) {
|
||||
|
||||
sellDownStairs = newVolumeStairs();
|
||||
|
||||
sellDownStairs.type = 'sell';
|
||||
sellDownStairs.direction = 'down';
|
||||
sellDownStairs.barsCount = 2;
|
||||
|
||||
sellDownStairs.begin = currentVolume.begin;
|
||||
sellDownStairs.end = nextVolume.end;
|
||||
|
||||
sellDownStairs.firstAmount = currentVolume.amountSell;
|
||||
sellDownStairs.lastAmount = nextVolume.amountSell;
|
||||
|
||||
} else {
|
||||
|
||||
sellDownStairs.barsCount++;
|
||||
sellDownStairs.end = nextVolume.end;
|
||||
sellDownStairs.lastAmount = nextVolume.amountSell;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (sellDownStairs !== undefined) {
|
||||
|
||||
if (sellDownStairs.barsCount > 2) {
|
||||
|
||||
stairsArray.push(sellDownStairs);
|
||||
}
|
||||
|
||||
sellDownStairs = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function recalculateScaleX() {
|
||||
|
||||
|
||||
var minValue = {
|
||||
x: EARLIEST_DATE.valueOf()
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf()
|
||||
};
|
||||
|
||||
plotArea.initializeX(
|
||||
minValue,
|
||||
maxValue,
|
||||
volumeTechnicalAnalisysChartLayer.container.frame.width
|
||||
);
|
||||
|
||||
plotAreaFrame.initializeX(
|
||||
minValue,
|
||||
maxValue,
|
||||
volumeTechnicalAnalisysChartLayer.container.frame.width
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function recalculateScaleY() {
|
||||
|
||||
var minValue = {
|
||||
y: 0
|
||||
};
|
||||
|
||||
var maxValue = {
|
||||
y: 0
|
||||
};
|
||||
|
||||
let timePeriodRatio = ONE_DAY_IN_MILISECONDS / timePeriod;
|
||||
|
||||
maxValue.y = marketIndex.maxVolume() / (timePeriodRatio / 10);
|
||||
|
||||
plotArea.initializeY(
|
||||
minValue,
|
||||
maxValue,
|
||||
viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topLeft.y
|
||||
);
|
||||
|
||||
plotAreaFrame.initializeY(
|
||||
minValue,
|
||||
maxValue,
|
||||
volumeTechnicalAnalisysChartLayer.container.frame.height
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function plotPatternChart() {
|
||||
|
||||
let opacity = '0.25';
|
||||
|
||||
let visibleHeight = viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topLeft.y;
|
||||
|
||||
let frameCorner1 = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
|
||||
let frameCorner2 = {
|
||||
x: volumeTechnicalAnalisysChartLayer.container.frame.width,
|
||||
y: volumeTechnicalAnalisysChartLayer.container.frame.height
|
||||
};
|
||||
|
||||
|
||||
/* Now the transformations. */
|
||||
|
||||
frameCorner1 = transformThisPoint(frameCorner1, volumeTechnicalAnalisysChartLayer.container.frame.container);
|
||||
frameCorner2 = transformThisPoint(frameCorner2, volumeTechnicalAnalisysChartLayer.container.frame.container);
|
||||
|
||||
let frameHeightInViewPort = frameCorner2.y - frameCorner1.y;
|
||||
|
||||
|
||||
if (stairsArray.length > 0) {
|
||||
|
||||
for (var i = 0; i < stairsArray.length; i++) {
|
||||
|
||||
stairs = stairsArray[i];
|
||||
|
||||
let volumeBarPointA1;
|
||||
let volumeBarPointA2;
|
||||
let volumeBarPointA3;
|
||||
let volumeBarPointA4;
|
||||
|
||||
if (stairs.type === 'buy') {
|
||||
|
||||
function calculateBuys(plot, height) {
|
||||
|
||||
volumeBarPointA1 = {
|
||||
x: stairs.begin + timePeriod / 2,
|
||||
y: 0
|
||||
};
|
||||
|
||||
volumeBarPointA2 = {
|
||||
x: stairs.begin + timePeriod / 2,
|
||||
y: stairs.firstAmount * 2
|
||||
};
|
||||
|
||||
volumeBarPointA3 = {
|
||||
x: stairs.end - timePeriod / 2,
|
||||
y: stairs.lastAmount * 2
|
||||
};
|
||||
|
||||
volumeBarPointA4 = {
|
||||
x: stairs.end - timePeriod / 2,
|
||||
y: 0
|
||||
};
|
||||
|
||||
|
||||
volumeBarPointA1 = plot.inverseTransform(volumeBarPointA1, height);
|
||||
volumeBarPointA2 = plot.inverseTransform(volumeBarPointA2, height);
|
||||
volumeBarPointA3 = plot.inverseTransform(volumeBarPointA3, height);
|
||||
volumeBarPointA4 = plot.inverseTransform(volumeBarPointA4, height);
|
||||
|
||||
volumeBarPointA1 = transformThisPoint(volumeBarPointA1, volumeTechnicalAnalisysChartLayer.container);
|
||||
volumeBarPointA2 = transformThisPoint(volumeBarPointA2, volumeTechnicalAnalisysChartLayer.container);
|
||||
volumeBarPointA3 = transformThisPoint(volumeBarPointA3, volumeTechnicalAnalisysChartLayer.container);
|
||||
volumeBarPointA4 = transformThisPoint(volumeBarPointA4, volumeTechnicalAnalisysChartLayer.container);
|
||||
|
||||
|
||||
if (volumeBarPointA4.x < viewPort.visibleArea.bottomLeft.x || volumeBarPointA1.x > viewPort.visibleArea.bottomRight.x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (calculateBuys(plotAreaFrame, volumeTechnicalAnalisysChartLayer.container.frame.height) === false) { continue; } // We try to see if it fits in the visible area.
|
||||
|
||||
if (volumeBarPointA1.y > viewPort.visibleArea.bottomLeft.y && frameHeightInViewPort > visibleHeight * 2 / 3) {
|
||||
|
||||
if (calculateBuys(plotArea, visibleHeight) === false) { continue; } // We snap t to the view port.
|
||||
|
||||
/* Now we set the real value of y. */
|
||||
|
||||
volumeBarPointA1.y = viewPort.visibleArea.bottomRight.y;
|
||||
volumeBarPointA2.y = viewPort.visibleArea.bottomRight.y - stairs.firstAmount * 2 * plotArea.scale.y;
|
||||
volumeBarPointA3.y = viewPort.visibleArea.bottomRight.y - stairs.lastAmount * 2 * plotArea.scale.y;
|
||||
volumeBarPointA4.y = viewPort.visibleArea.bottomRight.y;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let volumeBarPointB1;
|
||||
let volumeBarPointB2;
|
||||
let volumeBarPointB3;
|
||||
let volumeBarPointB4;
|
||||
|
||||
|
||||
if (stairs.type === 'sell') {
|
||||
|
||||
function calculateSells(plot, height) {
|
||||
|
||||
volumeBarPointB1 = {
|
||||
x: stairs.begin + timePeriod / 2,
|
||||
y: height
|
||||
};
|
||||
|
||||
volumeBarPointB2 = {
|
||||
x: stairs.begin + timePeriod / 2,
|
||||
y: height - stairs.firstAmount * 2
|
||||
};
|
||||
|
||||
volumeBarPointB3 = {
|
||||
x: stairs.end - timePeriod / 2,
|
||||
y: height - stairs.lastAmount * 2
|
||||
};
|
||||
|
||||
volumeBarPointB4 = {
|
||||
x: stairs.end - timePeriod / 2,
|
||||
y: height
|
||||
};
|
||||
|
||||
volumeBarPointB1 = plot.inverseTransform2(volumeBarPointB1, height);
|
||||
volumeBarPointB2 = plot.inverseTransform2(volumeBarPointB2, height);
|
||||
volumeBarPointB3 = plot.inverseTransform2(volumeBarPointB3, height);
|
||||
volumeBarPointB4 = plot.inverseTransform2(volumeBarPointB4, height);
|
||||
|
||||
volumeBarPointB1 = transformThisPoint(volumeBarPointB1, volumeTechnicalAnalisysChartLayer.container);
|
||||
volumeBarPointB2 = transformThisPoint(volumeBarPointB2, volumeTechnicalAnalisysChartLayer.container);
|
||||
volumeBarPointB3 = transformThisPoint(volumeBarPointB3, volumeTechnicalAnalisysChartLayer.container);
|
||||
volumeBarPointB4 = transformThisPoint(volumeBarPointB4, volumeTechnicalAnalisysChartLayer.container);
|
||||
|
||||
}
|
||||
|
||||
calculateSells(plotAreaFrame, volumeTechnicalAnalisysChartLayer.container.frame.height); // We try to see if it fits in the visible area.
|
||||
|
||||
if (volumeBarPointB1.y < viewPort.visibleArea.topLeft.y && frameHeightInViewPort > visibleHeight * 2 / 3) {
|
||||
|
||||
calculateSells(plotArea, visibleHeight); // We snap it to the view port.
|
||||
|
||||
/* Now we set the real value of y. */
|
||||
|
||||
volumeBarPointB1.y = viewPort.visibleArea.topLeft.y;
|
||||
volumeBarPointB2.y = viewPort.visibleArea.topLeft.y + stairs.firstAmount * 2 * plotArea.scale.y;
|
||||
volumeBarPointB3.y = viewPort.visibleArea.topLeft.y + stairs.lastAmount * 2 * plotArea.scale.y;
|
||||
volumeBarPointB4.y = viewPort.visibleArea.topLeft.y;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Everything must fit within the visible area */
|
||||
|
||||
if (stairs.type === 'buy') {
|
||||
|
||||
volumeBarPointA1 = viewPort.fitIntoVisibleArea(volumeBarPointA1);
|
||||
volumeBarPointA2 = viewPort.fitIntoVisibleArea(volumeBarPointA2);
|
||||
volumeBarPointA3 = viewPort.fitIntoVisibleArea(volumeBarPointA3);
|
||||
volumeBarPointA4 = viewPort.fitIntoVisibleArea(volumeBarPointA4);
|
||||
|
||||
} else {
|
||||
|
||||
volumeBarPointB1 = viewPort.fitIntoVisibleArea(volumeBarPointB1);
|
||||
volumeBarPointB2 = viewPort.fitIntoVisibleArea(volumeBarPointB2);
|
||||
volumeBarPointB3 = viewPort.fitIntoVisibleArea(volumeBarPointB3);
|
||||
volumeBarPointB4 = viewPort.fitIntoVisibleArea(volumeBarPointB4);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Now the drawing */
|
||||
|
||||
if (stairs.type === 'buy') {
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(volumeBarPointA1.x, volumeBarPointA1.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointA2.x, volumeBarPointA2.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointA3.x, volumeBarPointA3.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointA4.x, volumeBarPointA4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= stairs.begin && dateValue <= stairs.end) {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, ' + opacity + ')'; // Current bar accroding to time
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(64, 217, 26, ' + opacity + ')';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(64, 217, 26, ' + opacity + ')';
|
||||
|
||||
}
|
||||
|
||||
browserCanvasContext.fill();
|
||||
browserCanvasContext.strokeStyle = 'rgba(27, 105, 7, ' + opacity + ')';
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
|
||||
browserCanvasContext.moveTo(volumeBarPointB1.x, volumeBarPointB1.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointB2.x, volumeBarPointB2.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointB3.x, volumeBarPointB3.y);
|
||||
browserCanvasContext.lineTo(volumeBarPointB4.x, volumeBarPointB4.y);
|
||||
|
||||
browserCanvasContext.closePath();
|
||||
|
||||
if (datetime !== undefined) {
|
||||
|
||||
let dateValue = datetime.valueOf();
|
||||
|
||||
if (dateValue >= stairs.begin && dateValue <= stairs.end) {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, ' + opacity + ')'; // Current candle accroding to time
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(219, 18, 18, ' + opacity + ')';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(219, 18, 18, ' + opacity + ')';
|
||||
|
||||
}
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(130, 9, 9, ' + opacity + ')';
|
||||
|
||||
browserCanvasContext.fill();
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
browserCanvasContext.stroke();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Linear regression curve. SRC: Gekko
|
||||
*/
|
||||
|
||||
//var log = require('../../core/log');
|
||||
|
||||
var LRCIndicator = function(settings) {
|
||||
this.input = 'price';
|
||||
this.depth = settings;
|
||||
this.result = false;
|
||||
this.age = 0;
|
||||
this.history = [];
|
||||
this.x = [];
|
||||
/*
|
||||
* Do not use array(depth) as it might not be implemented
|
||||
*/
|
||||
for (var i = 0; i < this.depth; i++) {
|
||||
this.history.push(0.0);
|
||||
this.x.push(i);
|
||||
}
|
||||
|
||||
// log.debug("Created LRC indicator with h: ", this.depth);
|
||||
}
|
||||
|
||||
LRCIndicator.prototype.update = function(price) {
|
||||
// We need sufficient history to get the right result.
|
||||
if(this.result === false && this.age < this.depth) {
|
||||
|
||||
this.history[this.age] = price;
|
||||
this.age++;
|
||||
this.result = false;
|
||||
// log.debug("Waiting for sufficient age: ", this.age, " out of ", this.depth);
|
||||
return;
|
||||
}
|
||||
|
||||
this.age++;
|
||||
// shift history
|
||||
for (var i = 0; i < (this.depth - 1); i++) {
|
||||
this.history[i] = this.history[i+1];
|
||||
}
|
||||
this.history[this.depth-1] = price;
|
||||
|
||||
this.calculate(price);
|
||||
|
||||
// log.debug("Checking LRC: ", this.result.toFixed(8), "\tH: ", this.age);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Least squares linear regression fitting.
|
||||
*/
|
||||
function linreg(values_x, values_y) {
|
||||
var sum_x = 0;
|
||||
var sum_y = 0;
|
||||
var sum_xy = 0;
|
||||
var sum_xx = 0;
|
||||
var count = 0;
|
||||
|
||||
/*
|
||||
* We'll use those variables for faster read/write access.
|
||||
*/
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
var values_length = values_x.length;
|
||||
|
||||
if (values_length != values_y.length) {
|
||||
throw new Error('The parameters values_x and values_y need to have same size!');
|
||||
}
|
||||
|
||||
/*
|
||||
* Nothing to do.
|
||||
*/
|
||||
if (values_length === 0) {
|
||||
return [ [], [] ];
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the sum for each of the parts necessary.
|
||||
*/
|
||||
for (var v = 0; v < values_length; v++) {
|
||||
x = values_x[v];
|
||||
y = values_y[v];
|
||||
sum_x += x;
|
||||
sum_y += y;
|
||||
sum_xx += x*x;
|
||||
sum_xy += x*y;
|
||||
count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate m and b for the formula: y = x * m + b
|
||||
*
|
||||
*/
|
||||
var m = (count*sum_xy - sum_x*sum_y) / (count*sum_xx - sum_x*sum_x);
|
||||
var b = (sum_y/count) - (m*sum_x)/count;
|
||||
|
||||
return [m, b];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handle calculations
|
||||
*/
|
||||
LRCIndicator.prototype.calculate = function(price) {
|
||||
// get the reg
|
||||
var reg = linreg(this.x, this.history);
|
||||
|
||||
// y = a * x + b
|
||||
this.result = ((this.depth-1) * reg[0]) + reg[1];
|
||||
}
|
||||
+22
@@ -1,6 +1,8 @@
|
||||
|
||||
function newViewPort() {
|
||||
|
||||
const CONSOLE_LOG = true;
|
||||
|
||||
let ANIMATION_INCREMENT = 0.25;
|
||||
const TOP_MARGIN = 15;
|
||||
const BOTTOM_MARGIN = 0;
|
||||
@@ -20,6 +22,7 @@ function newViewPort() {
|
||||
fitIntoVisibleArea: fitIntoVisibleArea,
|
||||
displace: displace,
|
||||
displaceTarget: displaceTarget,
|
||||
displaceToDatetime: displaceToDatetime,
|
||||
animate: animate,
|
||||
draw: draw,
|
||||
initialize: initialize
|
||||
@@ -139,6 +142,25 @@ function newViewPort() {
|
||||
|
||||
}
|
||||
|
||||
function displaceToDatetime(datetime, plotArea) {
|
||||
|
||||
|
||||
targetOffset.x = targetOffset.x + displaceVector.x;
|
||||
|
||||
offsetIncrement = {
|
||||
x: (targetOffset.x - offset.x) / 10,
|
||||
y: (targetOffset.y - offset.y) / 10
|
||||
};
|
||||
|
||||
if (CONSOLE_LOG === true) {
|
||||
|
||||
console.log("viewPort -> displaceToDatetime x = " + targetOffset.x + " datetime = " + datetime);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function applyZoom(amount) {
|
||||
|
||||
//console.log("applyZoom amount: " + amount);
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
function newVolumeStairs() {
|
||||
|
||||
var volumeStairs = {
|
||||
type: undefined,
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
direction: undefined,
|
||||
barsCount: 0,
|
||||
firstAmount: 0,
|
||||
lastAmount: 0
|
||||
};
|
||||
|
||||
return volumeStairs;
|
||||
|
||||
}
|
||||
-22
@@ -58,8 +58,6 @@
|
||||
<script type="text/javascript" src="Dashboard.js"></script>
|
||||
<script type="text/javascript" src="AccumulatedVolumeBar.js"></script>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript" src="Azure/azure-storage.common.js"></script>
|
||||
<script type="text/javascript" src="Azure/azure-storage.file.js"></script>
|
||||
|
||||
@@ -70,26 +68,6 @@
|
||||
<script type="text/javascript" src="Panels/CurrentVolumePanel.js"></script>
|
||||
<script type="text/javascript" src="Panels/OrderBookPanel.js"></script>
|
||||
|
||||
<script type="text/javascript" src="VolumeTechnicalAnalisys/Stairs.js"></script>
|
||||
|
||||
<script type="text/javascript" src="CandleTechnicalAnalisys/Stairs.js"></script>
|
||||
<script type="text/javascript" src="CandleTechnicalAnalisys/Support.js"></script>
|
||||
<script type="text/javascript" src="CandleTechnicalAnalisys/Resistance.js"></script>
|
||||
<script type="text/javascript" src="CandleTechnicalAnalisys/HighLowFlag.js"></script>
|
||||
|
||||
<script type="text/javascript" src="ChartLayers/OrderBooksChartLayer.js"></script>
|
||||
<script type="text/javascript" src="ChartLayers/ForecastChartLayer.js"></script>
|
||||
<script type="text/javascript" src="ChartLayers/CandleTechnicalAnalisysChartLayer.js"></script>
|
||||
<script type="text/javascript" src="ChartLayers/VolumeTechnicalAnalisysChartLayer.js"></script>
|
||||
<script type="text/javascript" src="ChartLayers/AccumulatedVolumeChartLayer.js"></script>
|
||||
<script type="text/javascript" src="ChartLayers/CandeStickChartLayer.js"></script>
|
||||
<script type="text/javascript" src="ChartLayers/VolumeChartLayer.js"></script>
|
||||
<script type="text/javascript" src="ChartLayers/SupportResistanceChartLayer.js"></script>
|
||||
<script type="text/javascript" src="ChartLayers/HighLowChartLayer.js"></script>
|
||||
<script type="text/javascript" src="ChartLayers/AllTimeChartLayer.js"></script>
|
||||
|
||||
<script type="text/javascript" src="Indicators/LRC.js"></script>
|
||||
<script type="text/javascript" src="ChartLayers/LinearRegressionCurve.js"></script>
|
||||
<style type="text/css">
|
||||
browserCanvas {
|
||||
border: 1px solid black;
|
||||
|
||||
Reference in new issue
Block a user