Login Page - Create Account

Support Board


Date/Time: Tue, 26 Aug 2025 10:14:42 +0000



[Programming Help] - ACSIL help

View Count: 214

[2025-07-17 05:48:49]
User781731 - Posts: 70
I'm trying to calculate "Finish Ask Volume Bid Volume Difference (Finish AskVol BidVol Diff)" in my custom study.

My script correctly identifies the "Ask Volume Bid Volume Difference High" and "Ask Volume Bid Volume Difference Low"; which are the two elements needed for "Finish Ask Volume Bid Volume Difference (Finish AskVol BidVol Diff)" - see below.

These are the two formulas, one of which must be used to calculate the Finish value:

If the Ask Volume Bid Volume Difference High was more recently increased as compared to the Ask Volume Bid Volume Difference Low being more recently decreased, then Finish AskVol BidVol Diff equals the Ask Volume Bid Volume Difference for the bar minus the Ask Volume Bid Volume Difference High for the bar.

Otherwise, if the Ask Volume Bid Volume Difference Low was more recently decreased as compared to the Ask Volume Bid Volume Difference High being more recently increased, then Finish AskVol BidVol Diff equals the Ask Volume Bid Volume Difference for the bar minus the Ask Volume Bid Volume Difference Low for the bar.

Knowing which formula to use depends on which of the following two conditions is true:
- Ask Volume Bid Volume Difference High was more recently increased as compared to the Ask Volume Bid Volume Difference Low being more recently decreased
- Ask Volume Bid Volume Difference Low was more recently decreased as compared to the Ask Volume Bid Volume Difference High being more recently increased

This is what I'm unsure about. Can anyone help?

Here is the code:

#include "sierrachart.h"

SCDLLName("A-Finish")

// A-Finish: Tick-by-tick Finish Delta via Time & Sales only
SCSFExport scsf_AFinish(SCStudyInterfaceRef sc)
{
SCSubgraphRef Finish = sc.Subgraph[0];
SCSubgraphRef MaxDelta = sc.Subgraph[1];
SCSubgraphRef MinDelta = sc.Subgraph[2];
SCInputRef Lookback = sc.Input[0];

if (sc.SetDefaults)
{
sc.GraphName = "A-Finish";
sc.StudyDescription = "Finish Delta using only Time & Sales data.";
sc.AutoLoop = 0;
sc.UpdateAlways = 1;
sc.MaintainAdditionalChartDataArrays = 1;
sc.GraphRegion = 0;

Finish.Name = "Finish";
Finish.DrawStyle = DRAWSTYLE_LINE;
Finish.PrimaryColor = RGB(255,128,0);

MaxDelta.Name = "Max Delta";
MaxDelta.DrawStyle = DRAWSTYLE_IGNORE;
MinDelta.Name = "Min Delta";
MinDelta.DrawStyle = DRAWSTYLE_IGNORE;

Lookback.Name = "Bars to Log";
Lookback.SetInt(10);
Lookback.SetIntLimits(1,100);
return;
}

if (sc.IsFullRecalculation)
{
// Process all historical bars except the last (still forming)
for (int barToProcess = 0; barToProcess < sc.ArraySize - 1; ++barToProcess)
{
float runningDelta = 0.0f;
float maxDelta = 0.0f;
float minDelta = 0.0f;
int lastMaxIndex = -1;
int lastMinIndex = -1;
float totalAskVol = 0.0f;
float totalBidVol = 0.0f;

s_IntradayRecord record;
int subIndex = 0;
int readSuccess = 1;
bool firstIteration = true;
while (readSuccess)
{
IntradayFileLockActionEnum lockAction = IFLA_NO_CHANGE;
if (firstIteration) {
lockAction = IFLA_LOCK_READ_HOLD;
firstIteration = false;
}
readSuccess = sc.ReadIntradayFileRecordForBarIndexAndSubIndex(barToProcess, subIndex, record, lockAction);
if (readSuccess)
{
runningDelta += record.AskVolume;
runningDelta -= record.BidVolume;
totalAskVol += record.AskVolume;
totalBidVol += record.BidVolume;
if (subIndex == 0 || runningDelta > maxDelta)
{
maxDelta = runningDelta;
lastMaxIndex = subIndex;
}
if (subIndex == 0 || runningDelta < minDelta)
{
minDelta = runningDelta;
lastMinIndex = subIndex;
}
++subIndex;
}
}
sc.ReadIntradayFileRecordForBarIndexAndSubIndex(-1, -1, record, IFLA_RELEASE_AFTER_READ);
MaxDelta[barToProcess] = maxDelta;
MinDelta[barToProcess] = minDelta;
float finalDelta = totalAskVol - totalBidVol;
float finishValue = 0.0f;
if (finalDelta > 0)
finishValue = finalDelta - maxDelta;
else if (finalDelta < 0)
finishValue = finalDelta - minDelta;
else
finishValue = 0.0f;
Finish[barToProcess] = finishValue;
}
}
else
{
// Real-time: only process the most recent closed bar
static int lastProcessedBar = -1;
int currentIndex = sc.Index;
if (sc.GetBarHasClosedStatus(currentIndex - 1) != BHCS_BAR_HAS_CLOSED)
return;
int barToProcess = currentIndex - 1;
if (barToProcess == lastProcessedBar)
return;
lastProcessedBar = barToProcess;
float runningDelta = 0.0f;
float maxDelta = 0.0f;
float minDelta = 0.0f;
int lastMaxIndex = -1;
int lastMinIndex = -1;
float totalAskVol = 0.0f;
float totalBidVol = 0.0f;
s_IntradayRecord record;
int subIndex = 0;
int readSuccess = 1;
bool firstIteration = true;
while (readSuccess)
{
IntradayFileLockActionEnum lockAction = IFLA_NO_CHANGE;
if (firstIteration) {
lockAction = IFLA_LOCK_READ_HOLD;
firstIteration = false;
}
readSuccess = sc.ReadIntradayFileRecordForBarIndexAndSubIndex(barToProcess, subIndex, record, lockAction);
if (readSuccess)
{
runningDelta += record.AskVolume;
runningDelta -= record.BidVolume;
totalAskVol += record.AskVolume;
totalBidVol += record.BidVolume;
if (subIndex == 0 || runningDelta > maxDelta)
{
maxDelta = runningDelta;
lastMaxIndex = subIndex;
}
if (subIndex == 0 || runningDelta < minDelta)
{
minDelta = runningDelta;
lastMinIndex = subIndex;
}
++subIndex;
}
}
sc.ReadIntradayFileRecordForBarIndexAndSubIndex(-1, -1, record, IFLA_RELEASE_AFTER_READ);
MaxDelta[barToProcess] = maxDelta;
MinDelta[barToProcess] = minDelta;
float finalDelta = totalAskVol - totalBidVol;
float finishValue = 0.0f;
if (finalDelta > 0)
finishValue = finalDelta - maxDelta;
else if (finalDelta < 0)
finishValue = finalDelta - minDelta;
else
finishValue = 0.0f;
Finish[barToProcess] = finishValue;
}

// Log for last N bars (show correct values for all processed bars)
int N = Lookback.GetInt();
int currentIndex = sc.Index;
int startBar = max(0, currentIndex - N);
for (int b = startBar; b < currentIndex; ++b)
{
// Calculate Delta for the bar (total AskVol - BidVol)
float delta = Finish[b]; // Default to Finish for backward compatibility
if (b < sc.ArraySize) {
// Recalculate delta for the bar if possible
float totalAskVol = 0.0f;
float totalBidVol = 0.0f;
s_IntradayRecord record;
int subIndex = 0;
int readSuccess = 1;
bool firstIteration = true;
while (readSuccess)
{
IntradayFileLockActionEnum lockAction = IFLA_NO_CHANGE;
if (firstIteration) {
lockAction = IFLA_LOCK_READ_HOLD;
firstIteration = false;
}
readSuccess = sc.ReadIntradayFileRecordForBarIndexAndSubIndex(b, subIndex, record, lockAction);
if (readSuccess)
{
totalAskVol += record.AskVolume;
totalBidVol += record.BidVolume;
++subIndex;
}
}
sc.ReadIntradayFileRecordForBarIndexAndSubIndex(-1, -1, record, IFLA_RELEASE_AFTER_READ);
delta = totalAskVol - totalBidVol;
}
// Calculate Finish %
float finish = Finish[b];
float finishPercent = 0.0f;
if (finish < 0 && MaxDelta[b] != 0)
finishPercent = (fabsf(finish) / fabsf(MaxDelta[b])) * 100.0f;
else if (finish > 0 && MinDelta[b] != 0)
finishPercent = (fabsf(finish) / fabsf(MinDelta[b])) * 100.0f;
// If finish is 0 or divisor is 0, percent remains 0
SCString msg;
msg.Format("%s, Delta: %.0f, Max: %.0f, Min: %.0f, Finish: %.0f, Finish %%: %.0f",
sc.FormatDateTime(sc.BaseDateTimeIn[b]).GetChars(),
delta,
MaxDelta[b],
MinDelta[b],
finish,
finishPercent);
sc.AddMessageToLog(msg, 0);
}
}

Date Time Of Last Edit: 2025-07-17 12:04:08
[2025-07-17 07:17:16]
User781731 - Posts: 70
I tried this for the main Finish value:

If Delta > 0:   Finish = Delta - Max Delta
If Delta < 0:   Finish = Delta - Min Delta
If Delta == 0:  Finish = 0

And often it matches the Finish values found on the Numbers Bars Calculated Values study, but not always. Similarly, the formula I used to calculate Finish % produces values which sometimes match the NBCV study values, but not always.

So I'm back to the drawing board. I need a way to identify which of the following conditions is true:
- Ask Volume Bid Volume Difference High was more recently increased as compared to the Ask Volume Bid Volume Difference Low being more recently decreased
- Ask Volume Bid Volume Difference Low was more recently decreased as compared to the Ask Volume Bid Volume Difference High being more recently increased
Date Time Of Last Edit: 2025-07-17 12:08:01
[2025-07-17 14:22:38]
cmet - Posts: 719
I need a way to identify which of the following conditions is true:
- Ask Volume Bid Volume Difference High was more recently increased as compared to the Ask Volume Bid Volume Difference Low being more recently decreased
- Ask Volume Bid Volume Difference Low was more recently decreased as compared to the Ask Volume Bid Volume Difference High being more recently increased

After a quick look, have you tried using lastMaxIndex and lastMinIndex?

For finish values:

if (lastMaxIndex > lastMinIndex)
finishValue = finalDelta - maxDelta;
else if (lastMinIndex > lastMaxIndex)
finishValue = finalDelta - minDelta;
else
finishValue = 0.0f;

For %:

if (lastMaxIndex > lastMinIndex && fabsf(maxDelta) != 0.0f)
finishPercent = fabsf(finish) / fabsf(maxDelta) * 100.0f;
else if (lastMinIndex > lastMaxIndex && fabsf(minDelta) != 0.0f)
finishPercent = fabsf(finish) / fabsf(minDelta) * 100.0f;
else
finishPercent = 0.0f;

[2025-07-17 15:10:50]
User431178 - Posts: 764
If you need only this:


I'm trying to calculate "Finish Ask Volume Bid Volume Difference (Finish AskVol BidVol Diff)" in my custom study.
My script correctly identifies the "Ask Volume Bid Volume Difference High" and "Ask Volume Bid Volume Difference Low"; which are the two elements needed for "Finish Ask Volume Bid Volume Difference (Finish AskVol BidVol Diff)" - see below.

Then you are probably making the whole thing way more complicated than it needs to be.

Set this in sc.SetDefaults

sc.MaintainAdditionalChartDataArrays = 1;

The get delta finish like this:


const auto delta = sc.AskVolume[index] - sc.BidVolume[index];

if (sc.BaseDataIn[SC_ASK_BID_VOL_DIFF_MOST_RECENT_CHANGE][index] > 0)
DeltaFinish[index] = sc.BaseDataIn[SC_ASKBID_DIFF_HIGH][index] - delta;
else if (sc.BaseDataIn[SC_ASK_BID_VOL_DIFF_MOST_RECENT_CHANGE][index] < 0)
DeltaFinish[index] = sc.BaseDataIn[SC_ASKBID_DIFF_LOW][index] - delta;
else
DeltaFinish[index] = 0.0f;

Problem solved?

For definitions of data arrays used, you can check here:
ACSIL Interface Members - Variables and Arrays: sc.BaseDataIn[][] / sc.BaseData[][]

Of course, if there is some reason why you want to calculate it yourself from the underlying data, then I'll go away now.
Date Time Of Last Edit: 2025-07-17 15:11:57
[2025-07-18 03:20:18]
User781731 - Posts: 70
Thanks both. cmet I tried yours first and it worked!

To post a message in this thread, you need to log in with your Sierra Chart account:

Login

Login Page - Create Account