Hello, this is my first topic here so hopefully I am in the right category.
I have been working on modifying the community indicator ‘Better Delta Flow’ originally added by user Sethmo when I ran into an issue.
I am trying to add a volume profile for each bar on the opposite side of the delta profile. I was able to generate the profile graphic but I cannot figure out how to ‘flip’ the profile so that it originates on the right and points to the left.
From the AxesOrigin documentation, adding origin v: ‘right’ to the graphic declaration seems like it should be the answer but it is not working. I am at a loss with this one and really hoping someone here can help me figure this out.
Picture below, the volume profiles are in white:
And here is the source I currently have, AFAIK the only two relevant blocks of code are marked ‘Block 1’ and ‘Block 2’ in comments:
const predef = require("./tools/predef");
const SMA = require("./tools/SMA");
const { px, du, op, min, max } = require('./tools/graphics')
class barResDelta {
init() {
this.sma = SMA(this.props.period);
this.LabelType = this.props.DeltaLabel
this.rthOpen = +('' + this.props.marketOpenHours + (this.props.marketOpenMinutes < 10 ? '0' : '') + this.props.marketOpenMinutes)
this.rthClose = +('' + this.props.marketCloseHours + (this.props.marketCloseMinutes < 10 ? '0' : '') + this.props.marketCloseMinutes)
}
map(d) {
const mainContainer = {
tag: 'Container',
key: 'barsContainer',
children: [],
conditions: {
scaleRangeX: {
min: this.props.scaleFactorPx
},
scaleRangeY: {
min: this.contractInfo.tickSize
}
}
}
const barsContainer = {
tag: 'Container',
key: 'barsContainer',
children: [],
conditions: {
scaleRangeX: {
min: this.props.scaleFactorPx
},
scaleRangeY: {
min: this.contractInfo.tickSize
}
}
}
const textContainer = {
tag: 'Container',
key: 'textContainer',
children: [],
conditions: {
scaleRangeX: {
min: this.props.scaleFactorPx
},
scaleRangeY: {
min: this.contractInfo.tickSize
}
}
}
//BLOCK 1
const volBarsContainer = {
tag: 'Container',
key: 'volBarsContainer',
// origin: {
// cs: 'frame',
// h: 'right',
// v: 'top',
// },
children: [],
conditions: {
scaleRangeX: {
min: this.props.scaleFactorPx
},
scaleRangeY: {
min: this.contractInfo.tickSize
}
}
}
const candleContainer = {
tag: 'Container',
key: 'candleContainer',
children: [],
conditions: {
scaleRangeX: {
min: this.props.scaleFactorPx
},
scaleRangeY: {
min: this.contractInfo.tickSize
}
}
}
const vpocContainer = {
tag: 'Container',
key: 'vpocContainer',
children: [],
conditions: {
scaleRangeX: {
min: this.props.scaleFactorPx
},
scaleRangeY: {
min: this.contractInfo.tickSize
}
}
}
const unfinishedAuctions = {
tag: 'Container',
key: 'vpocContainer',
children: [],
conditions: {
scaleRangeX: {
min: this.props.scaleFactorPx
},
scaleRangeY: {
min: this.contractInfo.tickSize
}
}
}
//Vpoc code:
const profile = d.profile();
const VPOC = profile.reduce((result, value) => {
if (value.vol > result.vol) {
result = value;
}
return result;
}, { vol: 0 });
//Delta Code:
const profiles = d.profile()
const combinedProfs = {}
const modifiedSize = this.contractInfo.tickSize * this.props.priceLevelsPerBar
let last, barInit
profiles
.sort((a, b) => a.price - b.price)
.forEach(({price, vol, bidVol, askVol}) => {
if(!barInit) barInit = price
if(!last) last = price
if(last && last >= barInit) {
barInit = price
}
if(last && last <= barInit) {
let item = combinedProfs[barInit.toFixed(7).toString()]
if(!item) (
item = { vol: 0, askVol: 0, bidVol: 0 },
item.price = barInit,
combinedProfs[barInit.toFixed(7).toString()] = item
)
item.askVol += askVol
item.bidVol += bidVol
item.vol += vol
}
last = price
}
)
const high = Object.values(combinedProfs).reduce((a, {price}) => Math.max(a, price), 0)
const low = Object.values(combinedProfs).reduce((a, {price}) => Math.min(a, price), Infinity)
const range = high - low
const biggestDelta = Object.values(combinedProfs)
.map(({bidVol, askVol}) => Math.abs(bidVol - askVol))
.reduce((a, b) => Math.max(a, b), 0)
const biggestVolume = Object.values(combinedProfs).reduce((a, {vol}) => Math.max(a, vol), 0)
const nBars = range/(this.contractInfo.tickSize * this.props.priceLevelsPerBar)
Object.values(combinedProfs).forEach(({vol, bidVol, askVol, price}) => {
const delta = -(bidVol - askVol)
const textLength = delta.toString().length
const volTextLength = vol.toString().length
//Scaled barWidth
const barWidth = max(
px(2),
px(this.props.scaleFactorPx * Math.abs(delta/biggestDelta))
)
const volBarWidth = max(
px(2),
px(this.props.scaleFactorPx * (vol/biggestVolume))
)
const vpocbarWidth = barWidth + this.props.scaleFactorPx
const fontSize = this.props.fontSize
const fontColor = this.props.fontColor
const xOffset = .13
const xOffset2 = .05
const txtOffset = 1.5
//Location for Delta Bar Text
const textPt = {
x: op(
du(d.index()),
'+',
op(
px(fontSize),
'+',
px(15)
),
'+',
du(xOffset)
),
y: du(price+modifiedSize/2)
}
//BABEL: Add vol text later
//Gets Delta Label setting
let labelValue = 0
switch(this.LabelType){
case "all":
labelValue = 1
break;
case "vol":
labelValue = 2
break;
}
//Gets current timestamp in HH:MM
const timestamp = d.timestamp();
const hour = timestamp.getHours();
const minute = timestamp.getMinutes();
const time = +('' + hour + (minute < 10 ? '0' : '') + minute)
//Sets volThreshold depending on time of day
const volThreshold = (time > this.rthOpen && time < this.rthClose) ? this.props.RthVolThreshold : this.props.GbxVolThreshold
//Delta Bars Container
barsContainer.children.push({
tag: 'Shapes',
key: `bar${d.index()}${price}`,
primitives: [
{
tag: 'Rectangle',
position: {
x: this.props.EnableCandles ? op(du(d.index()), "+", du(xOffset)) : op(du(d.index()), "+", du(xOffset2)),
y: du(price + ((this.props.priceLevelsPerBar * this.contractInfo.tickSize)))
},
size: {
height: op(du(range/nBars), '-', px(1)),
width: barWidth
}
}
],
fillStyle: {
color: (delta > 0 && this.props.EnableNeutralDeltaColor==false) ? this.props.positiveDeltaColor : (delta < 0 && this.props.EnableNeutralDeltaColor==false) ? this.props.negativeDeltaColor : (delta > 0 && delta > volThreshold) ? this.props.positiveDeltaColor : delta < 0 && Math.abs(delta) > volThreshold ? this.props.negativeDeltaColor : this.props.neutralDeltaColor
}
})
//Text for Delta Bars
textContainer.children.push({
tag: 'Text',
key: `${d.index()}${price}`,
text: labelValue == 1 ? `${delta}` : labelValue == 2 & Math.abs(delta) > volThreshold ? `${delta}` : undefined,
point: textPt,
style: { fontSize, fill: fontColor },
textAlignment: 'centerMiddle'
})
//BLOCK 2
volBarsContainer.children.push({
tag:'Shapes',
key: `bar${d.index()}${price}`,
primitives: [
{
tag: 'Rectangle',
position: {
x: this.props.EnableCandles ? op(du(d.index()), "-", du(.40)) : op(du(d.index()), "-", du(xOffset2)),
y: du(price + ((this.props.priceLevelsPerBar * this.contractInfo.tickSize)))
},
size: {
height: op(du(range/nBars), '-', px(1)),
width: volBarWidth
}
}
],
fillStyle: {
color: this.props.volumeColor
}
})
//Candlesticks Container
candleContainer.children.push({
tag: 'Shapes',
key: `bar${d.index()}${price}`,
primitives: [
{
tag: 'Rectangle',
position: {
x: (price >= d.open() && price >= d.close()) ? du(d.index() + .05) : (price <= d.open() && price <= d.close()) ? du(d.index() + .05) : du(d.index()),
y: du(price + ((this.props.priceLevelsPerBar * this.contractInfo.tickSize)))
},
size: {
height: this.props.EnableCandles ? op(du(range/nBars), '+', px(0)) : px(0),
width: this.props.EnableCandles ? (price > d.open() && price < d.close()) ? px(6) : (price < d.open() && price > d.close()) ? px(6) : (price > d.open && price > d.close) ? px(1) : px(1) : px(0)
}
}
],
fillStyle: {
color: (this.props.EnableCandles && price > d.open() && price < d.close()) ? this.props.positiveCandleColor : (this.props.EnableCandles && price < d.open() && price > d.close()) ? this.props.negativeCandleColor : this.neutralDeltaColor
}
})
//VPOC Container
vpocContainer.children.push({
tag: 'Shapes',
key: `bar${d.index()}${price}`,
primitives: [
{
tag: 'Rectangle',
position: {
x: op(du(d.index()), "-", px(3)),
y: du(VPOC.price )
},
size: {
height: this.props.EnableVPOCBar ? px(2) : px(0),
width: px(this.props.scaleFactorPx*1.7)
}
}
],
fillStyle: {
color: this.props.VPOCBarColor
}
})
//Unfinished Auctions Container
unfinishedAuctions.children.push({
tag: 'Shapes',
key: `bar${d.index()}${price}`,
primitives: [
{
tag: 'Rectangle',
position: {
x: op(du(d.index()), "-", px(3)),
y: du(VPOC.price )
},
size: {
height: this.props.EnableVPOCBar ? px(2) : px(0),
width: px(this.props.scaleFactorPx*1.7)
}
}
],
fillStyle: {
color: this.props.VPOCBarColor
}
})
})
return {
graphics: {
items: [
barsContainer,
textContainer,
volBarsContainer,
candleContainer,
vpocContainer,
]
}
}
}
}
module.exports = {
inputType: 'bars',
name: "BabelFP",
description: "Babel FP",
calculator: barResDelta,
params: {
SetRTHMarketHours: predef.paramSpecs.enum({
spacer: '------------------------------------------------------------------------------------------------------------------------------------------------------'
}, 'spacer'),
marketOpenHours: predef.paramSpecs.number(8,1,1),
marketOpenMinutes: predef.paramSpecs.number(0,1,0),
marketCloseHours: predef.paramSpecs.number(17,1,1),
marketCloseMinutes: predef.paramSpecs.number(0,1,0),
VolumeOptions: predef.paramSpecs.enum({
spacer: '------------------------------------------------------------------------------------------------------------------------------------------------------'
}, 'spacer'),
priceLevelsPerBar: predef.paramSpecs.number(16,1,1),
scaleFactorPx: predef.paramSpecs.number(20, 5, 10),
positiveDeltaColor: predef.paramSpecs.color('#1AABE4'),
negativeDeltaColor: predef.paramSpecs.color('#FF004B'),
neutralDeltaColor: predef.paramSpecs.color('#999999'),
EnableNeutralDeltaColor: predef.paramSpecs.bool(true),
DeltaLabel: predef.paramSpecs.enum({
all: 'Enable All Labels',
vol: 'Labels > Vol Threshold'
}, 'vol'),
RthVolThreshold: predef.paramSpecs.number(120,1,0),
GbxVolThreshold: predef.paramSpecs.number(55,1,0),
fontSize: predef.paramSpecs.number(10,1,0),
fontColor: predef.paramSpecs.color('#FFFFFF'),
volumeColor: predef.paramSpecs.color('#FFFFFF'),
CandleOptions: predef.paramSpecs.enum({
spacer: '------------------------------------------------------------------------------------------------------------------------------------------------------'
}, 'spacer'),
EnableCandles: predef.paramSpecs.bool(true),
positiveCandleColor: predef.paramSpecs.color('#1AABE4'),
negativeCandleColor: predef.paramSpecs.color('#FF004B'),
VPOCBarOptions: predef.paramSpecs.enum({
spacer: '------------------------------------------------------------------------------------------------------------------------------------------------------'
}, 'spacer'),
EnableVPOCBar: predef.paramSpecs.bool(true),
VPOCBarColor: predef.paramSpecs.color('#F8E71C'),
},
schemeStyles: predef.styles.solidLine("#000"),
requirements: {
volumeProfiles: true
}
};