Login Page - Create Account

Support Board


Date/Time: Sat, 27 Apr 2024 20:05:36 +0000



[User Discussion] - TrueLive 2014 for SC V1149 Onwards

View Count: 3965

[2014-06-23 03:52:00]
Kiwi - Posts: 374
IB data comes in two forms: live which is snapshot based so may miss high or low prices with a 100ms snapshot, and true or 5 second data which contains accurate OHLCVT data but is 5 seconds "late." In the past SC has been one of the only charting platforms that let you combine the two to give you "good" IB data using my various TrueLive functions to do it.

With version 1148 the SC team chose to improve efficiencies and got rid of the ability to seperately download -TD charts containing 5 second data. Instead we can now select to store 5 second data or live data. If you watch the chart when storing 5 second data you note the bars start 5 seconds after they "should" and you have 5 seconds pauses between updates. All the while your bid / ask is updating as is the SC time and sales. At their suggestion I have created a new dll with a new function TrueLive2014 which you run in SC and will display the updates from the live feed in real time.

So the chart stores 5 second data, the 5 second data corrects for any missing ticks, but the T&S information is used to create bars that are on time and responsive.

To use it:

Save the dll in your data folder
Set your Data/Trade Service Settings to:
-"Record True Real-Time Data in Intraday Chart"
- Number of Stored Time and Sales to > 0 (I use 100)
Then > Analysis > Studies > Add Custom Study > and find the study shown
Then adjust the colors (first 2 are the up color, next 2 are the down color)

Note that I included a version "pvm" for people who use price multipliers or volume multipliers and find that the original version isn't working properly.

finding it: http://i.imgur.com/363y4J6.png
http://www.sierrachart.com/Download.php?Folder=SupportBoard&download=2850

colors: http://i.imgur.com/5MkI8kF.png
http://www.sierrachart.com/Download.php?Folder=SupportBoard&download=2851


Date Time Of Last Edit: 2014-06-23 09:59:17
Attachment Deleted.
Attachment Deleted.
Attachment Deleted.
Attachment Deleted.
Attachment Deleted.
Attachment Deleted.
Attachment Deleted.
Attachment Deleted.
Attachment Deleted.
Attachment Deleted.
Attachment Deleted.
Attachment Deleted.
[2014-06-23 05:52:53]
Kiwi - Posts: 374

Found issue where, when new session starts it can repeately display a single tick from the Time & Sales (which disappears when you press Insert to refresh the chart). Fixed this by only allowing one T&S bar to be started.

/*==========================================================================*/
SCSFExport scsf_TrueLive_2014(SCStudyInterfaceRef sc) {

SCFloatArray& O = sc.BaseDataIn[0], H = sc.BaseDataIn[1],
L = sc.BaseDataIn[2], C = sc.BaseDataIn[3],
V = sc.BaseDataIn[4], T = sc.BaseDataIn[5];
SCSubgraphRef oO = sc.Subgraph[0], oH = sc.Subgraph[1],
oL = sc.Subgraph[2], oC = sc.Subgraph[3],
oV = sc.Subgraph[4], oT = sc.Subgraph[5];
SCSubgraphRef o = sc.Subgraph[10], h = sc.Subgraph[11],
          l = sc.Subgraph[12], c = sc.Subgraph[13],
          v = sc.Subgraph[14], t = sc.Subgraph[15],
          o2 = sc.Subgraph[22], o3 = sc.Subgraph[23],
          o4 = sc.Subgraph[24], o5 = sc.Subgraph[25];

  if (sc.SetDefaults) {
sc.GraphName = "TrueLive 2014";
sc.StudyDescription = "True Live using Custom Chart 2014 Release";
sc.Subgraph[0].Name = "Open";
    sc.Subgraph[1].Name = "High";
sc.Subgraph[2].Name = "Low";
    sc.Subgraph[3].Name = "Last";
sc.Subgraph[4].Name = "Volume";
    sc.Subgraph[5].Name = "# of Trades";
sc.Subgraph[6].Name = "HL";
sc.Subgraph[7].Name = "HLC";
sc.Subgraph[8].Name = "OHLC";
o2.Name="o2"; o3.Name="o3"; o4.Name="o4"; o5.Name="o5";
    sc.GraphRegion = 0; // First region
sc.GraphDrawType = GDT_CANDLESTICK;
sc.DisplayAsMainPriceGraph=1;
sc.IsCustomChart = 1;
sc.UpdateAlways=1;
sc.DrawZeros=0;
return;
}
// sc.FreeDLL = 1;

int as = sc.ArraySize-1;
  int ap = as - 1;
int& seqno = sc.PersistVars->i1;
int& tnsno = sc.PersistVars->i2;

if (sc.UpdateStartIndex == 0) {
int os = 0; // os stores the position of the out array
    tnsno = seqno = 0;
sc.ResizeArrays(0);
for ( ; os < sc.ArraySize; os++) {
sc.AddElements(1);
      sc.DateTimeOut[os] = sc.BaseDateTimeIn[os];
oO[os] = O[os];
      oH[os] = H[os];
oL[os] = L[os];
      oC[os] = C[os];
oV[os] = V[os];
      oT[os] = T[os];
sc.Subgraph[SC_HL][os] = (oH[os] + oL[os]) / 2;
sc.Subgraph[SC_HLC][os] = (oH[os] + oL[os] + oC[os]) / 3;
sc.Subgraph[SC_OHLC][os] = (oH[os] + oL[os] + oC[os] + oO[os]) / 4;
}
}

  // First deal with underlying data
int os = sc.OutArraySize-1;
  // add an extra bar if the underlying is later than the output bar
  if( sc.BaseDateTimeIn[as] > sc.DateTimeOut[os] ) {
os++;
    sc.AddElements(1);
sc.DateTimeOut[os] = sc.BaseDateTimeIn[as];
    oO[os] = oH[os] = oL[os] = oC[os] = O[as];
}
  int op = os - 1;
if (sc.DateTimeOut[os] == sc.BaseDateTimeIn[as]) {
    // Only apply 5 second data if its changed (ie, dont reset live changes)
    if(h[os] != H[as] || l[os] != L[as] || c[os] != C[as] || v[os] != V[as])
    {
      tnsno = 0;
      h[os] = H[as]; l[os] = L[as];
      c[os] = C[as]; v[os] = V[as];
      // update this bar
      oO[os] = O[as]; oH[os] = H[as];
      oL[os] = L[as]; oC[os] = C[as];
      oV[os] = V[as]; oT[os] = T[as];
      // match prior bar to 5 second data
      oO[op] = O[ap]; oH[op] = H[ap];
      oL[op] = L[ap]; oC[op] = C[ap];
      oV[op] = V[ap]; oT[op] = T[ap];
    }
  }
  else if (sc.DateTimeOut[op] == sc.BaseDateTimeIn[as]) {
    // must be in first 5 seconds of new bar so
    // update prior bar with 5 second data
    oH[op] = max(H[as], oH[op]);
    oL[op] = min(L[as], oL[op]);
    oO[op] = O[as]; oC[op] = C[as];
    oV[op] = V[as]; oT[op] = T[as];
  }

  // then look at live data
  SCTimeAndSalesArray TSArray;
  sc.GetTimeAndSales(TSArray);
  int ts = TSArray.GetArraySize() - 1;
  if (ts >= 0 && TSArray[ts].Sequence > seqno) {
    int tp = ts, adjt = sc.TimeScaleAdjustment.GetTime();
    double adj = sc.TimeScaleAdjustment;
    while (TSArray[tp].Sequence > seqno) {tp--;}
    // iterate through each time & sales value
    for ( ; tp <= ts; tp++) {
      if (tnsno == 0 && TSArray[tp].DateTime.GetTime() + adjt >=
         sc.DateTimeOut[os].GetTime() + sc.SecondsPerBar) {
        tnsno = 1;
        os++;
        sc.AddElements(1);
        sc.DateTimeOut[os].SetDate(sc.DateTimeOut[as].GetDate());
        sc.DateTimeOut[os].SetTime(sc.DateTimeOut[as].GetTime() +
           sc.SecondsPerBar);
        oO[os] = oH[os] = oL[os] = oC[os] = TSArray[tp].Price;
        oV[os] = TSArray[tp].Volume;
      }
      else if (TSArray[tp].DateTime.GetTime() + adjt >=
           sc.DateTimeOut[os].GetTime()) {
        oH[os] = max(TSArray[tp].Price, oH[os]);
        if (TSArray[tp].Price > 0 && oL[os] > 0)
          oL[os] = min(TSArray[tp].Price, oL[os]);
        else
          oL[os] = max(TSArray[tp].Price, oL[os]);
        oC[os] = TSArray[tp].Price;
        oV[os] += TSArray[tp].Volume;
      }
    }
    seqno = TSArray[ts].Sequence;
  }
  sc.Subgraph[SC_HL][os] = (oH[os] + oL[os]) / 2;
  sc.Subgraph[SC_HLC][os] = (oH[os] + oL[os] + oC[os]) / 3;
  sc.Subgraph[SC_OHLC][os] = (oH[os] + oL[os] + oC[os] + oO[os]) / 4;
  sc.Subgraph[SC_HL][op] = (oH[op] + oL[op]) / 2;
  sc.Subgraph[SC_HLC][op] = (oH[op] + oL[op] + oC[op]) / 3;
  sc.Subgraph[SC_OHLC][op] = (oH[op] + oL[op] + oC[op] + oO[op]) / 4;
}



New DLL and cpp (code file):


Date Time Of Last Edit: 2014-06-23 10:12:40
attachmentkiwi14.dll - Attached On 2014-06-23 05:52:08 UTC - Size: 158 KB - 503 views
attachmentkiwi14.cpp - Attached On 2014-06-23 05:52:31 UTC - Size: 10.64 KB - 526 views
[2014-06-23 17:32:37]
xroads - Posts: 5
Kiwi, thank you for this.
[2014-06-24 00:58:03]
Kiwi - Posts: 374
No problem Xroads ... I need it so I might as well share it.

There is one issue I know of at present. IB can produce a spurious time and sales value "between sessions". In HSI this is a value at the beginning of lunchtime or in the few seconds before the new session starts. At present the solution is to press insert (rewrite chart) just after the new session starts which will rewrite the chart with no spurious bars present.

I am testing a version where if a T&S bar is created and a 5 second bar is not received within the next 10 seconds the (now known to be) spurious bar will be removed. Similarly if the first 5 second bar of the session appears, needs to generate a new bar and the prior bar isn't based on 5 second data it will remove it. I need to test it for a while because "complex solutions" often reveal issues I hadn't previously thought of so I'll release a new version in the weekend if it works.

In the mean time, if you notice a "wrong bar" (which will normally print a single price) or if you just want to be sure, just press Insert.

Note: currently I increment volume if there is volume associated with the T&S values. I will stop that as it exposes you to rollover volume and other elements that might be filtered from the 5 second data feed. So in the next iteration volume will update only with the 5 second bars (much more accurate) unless someone objects here (please explain why).
Date Time Of Last Edit: 2014-06-24 04:42:26
[2014-06-25 06:59:39]
Kiwi - Posts: 374
All of those things improved the presentation. I also changed it so that the 5 second close can't ever set the close on the active bar - its always set by T&S. Why? Because I noted that as the new T&S based bar starts (first 5 seconds) you can get two 5 second bars and sometimes the close would swing wildly before the first 5 sec packet for the new bar arrived. Basically I think that one 5 sec bar and a T&S value (or 2) get out of sequence.

When I eliminated the ability of that 5 second packet to reset the close the behaviour settles nicely and all the closes were orderly.

So heres the new edition.

/*==========================================================================*/
SCSFExport scsf_TrueLive_2014(SCStudyInterfaceRef sc) {

SCFloatArray& O = sc.BaseDataIn[0], H = sc.BaseDataIn[1],
L = sc.BaseDataIn[2], C = sc.BaseDataIn[3],
V = sc.BaseDataIn[4], T = sc.BaseDataIn[5];
SCSubgraphRef oO = sc.Subgraph[0], oH = sc.Subgraph[1],
oL = sc.Subgraph[2], oC = sc.Subgraph[3],
oV = sc.Subgraph[4], oT = sc.Subgraph[5];
SCSubgraphRef o = sc.Subgraph[10], h = sc.Subgraph[11],
l = sc.Subgraph[12], c = sc.Subgraph[13],
v = sc.Subgraph[14], t = sc.Subgraph[15],
o2 = sc.Subgraph[22], o3 = sc.Subgraph[23],
o4 = sc.Subgraph[24], o5 = sc.Subgraph[25];

if (sc.SetDefaults) {
sc.GraphName = "TrueLive 2014";
sc.StudyDescription = "True Live using Custom Chart 2014 Release";
sc.Subgraph[0].Name = "Open";
sc.Subgraph[1].Name = "High";
sc.Subgraph[2].Name = "Low";
sc.Subgraph[3].Name = "Last";
sc.Subgraph[4].Name = "Volume";
sc.Subgraph[5].Name = "# of Trades";
sc.Subgraph[6].Name = "HL";
sc.Subgraph[7].Name = "HLC";
sc.Subgraph[8].Name = "OHLC";
o2.Name="o2"; o3.Name="o3";
o4.Name="o4"; o5.Name="o5";
sc.GraphRegion = 0; // First region
sc.GraphDrawType = GDT_CANDLESTICK;
sc.DisplayAsMainPriceGraph=1;
sc.IsCustomChart = 1;
sc.UpdateAlways=1;
sc.DrawZeros=0;
return;
}
// sc.FreeDLL = 1;

int as = sc.ArraySize-1;
int ap = as - 1;
int& seqno = sc.PersistVars->i1;
int& tnsno = sc.PersistVars->i2;
SCTimeAndSalesArray TSArray;
sc.GetTimeAndSales(TSArray);
int ts = TSArray.GetArraySize() - 1;

if (sc.UpdateStartIndex == 0) {
int os = 0; // os stores the position of the out array
tnsno = seqno = 0;
if (ts >= 0)
seqno = TSArray[ts].Sequence;
sc.ResizeArrays(0);
for ( ; os < sc.ArraySize; os++) {
sc.AddElements(1);
sc.DateTimeOut[os] = sc.BaseDateTimeIn[os];
oO[os] = O[os];
oH[os] = H[os];
oL[os] = L[os];
oC[os] = C[os];
oV[os] = V[os];
oT[os] = T[os];
sc.Subgraph[SC_HL][os] = (oH[os] + oL[os]) / 2;
sc.Subgraph[SC_HLC][os] = (oH[os] + oL[os] + oC[os]) / 3;
sc.Subgraph[SC_OHLC][os] = (oH[os] + oL[os] + oC[os] + oO[os]) / 4;
}
}

// First deal with underlying data
int os = sc.OutArraySize-1;
// add an extra bar if the underlying is later than the output bar
if( sc.BaseDateTimeIn[as] > sc.DateTimeOut[os] ) {
// only add element if there isn't a spurious t&s element present
if(tnsno == 0) os++;
sc.AddElements(1);
sc.DateTimeOut[os] = sc.BaseDateTimeIn[as];
oO[os] = oH[os] = oL[os] = oC[os] = O[as];
}
int op = os - 1;
if (sc.DateTimeOut[os] == sc.BaseDateTimeIn[as]) {
// Only apply 5 second data if its changed (ie dont reset live changes)
if(c[os] != C[as] || v[os] != V[as] || h[os] != H[as] || l[os] != L[as])
{
tnsno = 0;
h[os] = H[as]; l[os] = L[as];
c[os] = C[as]; v[os] = V[as];
// update this bar
oO[os] = O[as]; oH[os] = H[as];
oL[os] = L[as]; // oC[os] = C[as];
oV[os] = V[as]; oT[os] = T[as];
// match prior bar to 5 second data
oO[op] = O[ap]; oH[op] = H[ap];
oL[op] = L[ap]; oC[op] = C[ap];
oV[op] = V[ap]; oT[op] = T[ap];
}
}
else if (sc.DateTimeOut[op] == sc.BaseDateTimeIn[as]) {
// must be in first 5 seconds of new bar so
// update prior bar with 5 second data
oO[op] = O[as];
oH[op] = max(H[as], oH[op]);
oL[op] = min(L[as], oL[op]);
if (sc.CurrentSystemDateTime.GetTime() >
sc.BaseDateTimeIn[as].GetTime() + sc.SecondsPerBar + 15) {
oC[op] = C[as];
}
oV[op] = V[as]; oT[op] = T[as];
}

// then look at live data
if (ts >= 0 && TSArray[ts].Sequence > seqno) {
int tp = ts;
int adjt = sc.TimeScaleAdjustment.GetTime();
double adj = sc.TimeScaleAdjustment;
while (TSArray[tp].Sequence > seqno) {tp--;}
// iterate through each time & sales value
for ( ; tp <= ts; tp++) {
// if its a new bar start one
if (tnsno == 0 && TSArray[tp].DateTime.GetTime() + adjt >=
sc.DateTimeOut[os].GetTime() + sc.SecondsPerBar) {
tnsno = 1; // flag that a time&sales bar has been created
os++;
sc.AddElements(1);
sc.DateTimeOut[os].SetDate(sc.DateTimeOut[as].GetDate());
sc.DateTimeOut[os].SetTime(sc.DateTimeOut[as].GetTime() +
sc.SecondsPerBar);
// note that for new session this bar time is wrong
// and it will be cancelled as spurious so the new bar
// will be formed when the first 5 sec bar arrives
oO[os] = oH[os] = oL[os] = oC[os] = TSArray[tp].Price;
oV[os] = TSArray[tp].Volume;
}
// else update high low and close for this bar
else if (TSArray[tp].DateTime.GetTime() + adjt >=
sc.DateTimeOut[os].GetTime() &&
TSArray[tp].DateTime.GetTime() + adjt <
sc.DateTimeOut[os].GetTime() + sc.SecondsPerBar) {
oH[os] = max(TSArray[tp].Price, oH[os]);
if (TSArray[tp].Price > 0 && oL[os] > 0)
oL[os] = min(TSArray[tp].Price, oL[os]);
else
oL[os] = max(TSArray[tp].Price, oL[os]);
oC[os] = TSArray[tp].Price;
}
}
seqno = TSArray[ts].Sequence;
}
// Check for spurious time & sales based bars (> 10 seconds with no 5sec)
if(tnsno != 0) {
// spurious if no 5 second confirmation within 15 seconds
if(sc.CurrentSystemDateTime.GetDate() > sc.DateTimeOut[os].GetDate() ||
sc.CurrentSystemDateTime.GetTime() > sc.DateTimeOut[os].GetTime()
+ 15) {
sc.AddElements(-1);
tnsno = 0;
}
}

sc.Subgraph[SC_HL][os] = (oH[os] + oL[os]) / 2;
sc.Subgraph[SC_HLC][os] = (oH[os] + oL[os] + oC[os]) / 3;
sc.Subgraph[SC_OHLC][os] = (oH[os] + oL[os] + oC[os] + oO[os]) / 4;
sc.Subgraph[SC_HL][op] = (oH[op] + oL[op]) / 2;
sc.Subgraph[SC_HLC][op] = (oH[op] + oL[op] + oC[op]) / 3;
sc.Subgraph[SC_OHLC][op] = (oH[op] + oL[op] + oC[op] + oO[op]) / 4;
}



Date Time Of Last Edit: 2014-06-28 05:33:37
attachmentkiwi14.dll - Attached On 2014-06-25 06:56:53 UTC - Size: 157 KB - 492 views
attachmentkiwi14.cpp - Attached On 2014-06-25 06:58:04 UTC - Size: 12.6 KB - 544 views
attachmentkiwi14.dll - Attached On 2014-06-25 06:56:53 UTC - Size: 157 KB - 492 views
attachmentkiwi14.cpp - Attached On 2014-06-25 06:58:04 UTC - Size: 12.6 KB - 544 views
[2014-06-28 00:49:10]
Kiwi - Posts: 374
Having run this version now for two days I'm happy that it provides a responsive accurate rendition of price so there isn't an update.

In a fast market the first 5 second period after the last bar forms can result in a correction to the last close and this open but its seems to accurately reflect the best data that SC is receiving from IB.

If anyone has issues then please post here.

Good Trading.
Date Time Of Last Edit: 2014-06-28 05:17:53
[2014-06-28 07:54:04]
Sierra Chart Engineering - Posts: 104368
Is the source code posted in post #6, not the attached files, the latest code for True Live?
Sierra Chart Support - Engineering Level

Your definitive source for support. Other responses are from users. Try to keep your questions brief and to the point. Be aware of support policy:
https://www.sierrachart.com/index.php?l=PostingInformation.php#GeneralInformation

For the most reliable, advanced, and zero cost futures order routing, *change* to the Teton service:
Sierra Chart Teton Futures Order Routing
[2014-06-29 03:46:56]
Kiwi - Posts: 374
The code posted in 6 should match the "non-pvm" code from the cpp file attached for post 6. One difference might be that I replaced all the tabs with spaces after I first posted it because I had a mix of tabs and spaces which was confusing the board's formatting.

If you were generalizing it you might want to use the price and volume format multipliers. I put them into the second (pvm) version of truelive but didn't really test them because I don't use them.

TSArray[tp].Price * sc.RealTimePriceMultiplier;
TSArray[tp].Volume * sc.MultiplierFromVolumeValueFormat();

Here's my copy of the cpp though.
Date Time Of Last Edit: 2014-06-29 03:51:07
attachmentkiwi14.cpp - Attached On 2014-06-29 03:48:57 UTC - Size: 14.25 KB - 520 views
[2014-06-30 02:44:49]
Kiwi - Posts: 374
Engineering, I've been watching IB's version against this one and we're better ... they have the ability for a bar to be left diverged from the true data (not sure how).

One issue I've found. If I delete and download the data I need to refresh the chart. Is there an acsil function that lets me know that data has been downloaded so that I can autorefresh the chart when that has happened?

If there isn't an acsil member I'll just do it by forcing a recalc of the entire array if the newest time exceeds a most recently recorded bar time by more than 2 bar periods --- this works ok on my chart.
Date Time Of Last Edit: 2014-06-30 04:01:33
[2014-06-30 04:47:42]
Sierra Chart Engineering - Posts: 104368
We have included the latest True Live studies in the User Contributed Studies with Sierra Chart.

In ACSIL there is this member:
sc.DownloadingHistoricalData

It is nonzero when data is being downloaded.

There should be a recalculation of custom charts after a historical data download. But the way that works is kind of intricate . We would have to confirm that with code review.
Sierra Chart Support - Engineering Level

Your definitive source for support. Other responses are from users. Try to keep your questions brief and to the point. Be aware of support policy:
https://www.sierrachart.com/index.php?l=PostingInformation.php#GeneralInformation

For the most reliable, advanced, and zero cost futures order routing, *change* to the Teton service:
Sierra Chart Teton Futures Order Routing
[2014-06-30 05:43:44]
Kiwi - Posts: 374
Thanks for that. To avoid the risk of getting it wrong I've just used a persistent variable to store "lasttime" that a bar was received. When you reload the data it picks up an earlier time which is more than 2 bars from the last bar of the reloaded data - this forces it to rebuild the chart so there is no possibility of a discontinutity.

The changes are on the lines including the integer lasttime.

If you don't change to this version you simply need to press insert to refresh the chart after you reload the data.


/*==========================================================================*/
SCSFExport scsf_TrueLive_2014(SCStudyInterfaceRef sc) {

SCFloatArray& O = sc.BaseDataIn[0], H = sc.BaseDataIn[1],
L = sc.BaseDataIn[2], C = sc.BaseDataIn[3],
V = sc.BaseDataIn[4], T = sc.BaseDataIn[5];
SCSubgraphRef oO = sc.Subgraph[0], oH = sc.Subgraph[1],
oL = sc.Subgraph[2], oC = sc.Subgraph[3],
oV = sc.Subgraph[4], oT = sc.Subgraph[5];
SCSubgraphRef o = sc.Subgraph[10], h = sc.Subgraph[11],
l = sc.Subgraph[12], c = sc.Subgraph[13],
v = sc.Subgraph[14], t = sc.Subgraph[15],
o2 = sc.Subgraph[22], o3 = sc.Subgraph[23],
o4 = sc.Subgraph[24], o5 = sc.Subgraph[25];

if (sc.SetDefaults) {
sc.GraphName = "TrueLive 2014";
sc.StudyDescription = "True Live using Custom Chart 2014 Release";
sc.Subgraph[0].Name = "Open";
sc.Subgraph[1].Name = "High";
sc.Subgraph[2].Name = "Low";
sc.Subgraph[3].Name = "Last";
sc.Subgraph[4].Name = "Volume";
sc.Subgraph[5].Name = "# of Trades";
sc.Subgraph[6].Name = "HL";
sc.Subgraph[7].Name = "HLC";
sc.Subgraph[8].Name = "OHLC";
o2.Name="o2"; o3.Name="o3";
o4.Name="o4"; o5.Name="o5";
sc.GraphRegion = 0; // First region
sc.GraphDrawType = GDT_CANDLESTICK;
sc.DisplayAsMainPriceGraph=1;
sc.IsCustomChart = 1;
sc.UpdateAlways=1;
sc.DrawZeros=0;
return;
}
// sc.FreeDLL = 1;

int as = sc.ArraySize-1;
int ap = as - 1;
int& seqno = sc.PersistVars->i1;
int& tnsno = sc.PersistVars->i2;
int& lasttime = sc.PersistVars->i10;
SCTimeAndSalesArray TSArray;
sc.GetTimeAndSales(TSArray);
int ts = TSArray.GetArraySize() - 1;

// lasttime is used to detect that data has been reloaded so
  // the chart needs to be refreshed
  if (sc.UpdateStartIndex == 0 || sc.BaseDateTimeIn[as].GetTime() >
     lasttime + sc.SecondsPerBar + sc.SecondsPerBar) {
int os = 0; // os stores the position of the out array
tnsno = seqno = 0;
if (ts >= 0)
seqno = TSArray[ts].Sequence;
sc.ResizeArrays(0);
for ( ; os < sc.ArraySize; os++) {
sc.AddElements(1);
sc.DateTimeOut[os] = sc.BaseDateTimeIn[os];
oO[os] = O[os];
oH[os] = H[os];
oL[os] = L[os];
oC[os] = C[os];
oV[os] = V[os];
oT[os] = T[os];
sc.Subgraph[SC_HL][os] = (oH[os] + oL[os]) / 2;
sc.Subgraph[SC_HLC][os] = (oH[os] + oL[os] + oC[os]) / 3;
sc.Subgraph[SC_OHLC][os] = (oH[os] + oL[os] + oC[os] + oO[os]) / 4;
lasttime = sc.DateTimeOut[os].GetTime();
}
}

// First deal with underlying data
int os = sc.OutArraySize-1;
lasttime = sc.BaseDateTimeIn[as].GetTime();
// add an extra bar if the underlying is later than the output bar
if( sc.BaseDateTimeIn[as] > sc.DateTimeOut[os] ) {
// only add element if there isn't a spurious t&s element present
if(tnsno == 0) os++;
sc.AddElements(1);
sc.DateTimeOut[os] = sc.BaseDateTimeIn[as];
oO[os] = oH[os] = oL[os] = oC[os] = O[as];
}
int op = os - 1;
if (sc.DateTimeOut[os] == sc.BaseDateTimeIn[as]) {
// Only apply 5 second data if its changed (ie dont reset live changes)
if(c[os] != C[as] || v[os] != V[as] || h[os] != H[as] || l[os] != L[as])
{
tnsno = 0;
h[os] = H[as]; l[os] = L[as];
c[os] = C[as]; v[os] = V[as];
// update this bar
oO[os] = O[as]; oH[os] = H[as];
oL[os] = L[as]; // oC[os] = C[as];
oV[os] = V[as]; oT[os] = T[as];
// match prior bar to 5 second data
oO[op] = O[ap]; oH[op] = H[ap];
oL[op] = L[ap]; oC[op] = C[ap];
oV[op] = V[ap]; oT[op] = T[ap];
}
}
else if (sc.DateTimeOut[op] == sc.BaseDateTimeIn[as]) {
// must be in first 5 seconds of new bar so
// update prior bar with 5 second data
oO[op] = O[as];
oH[op] = max(H[as], oH[op]);
oL[op] = min(L[as], oL[op]);
if (sc.CurrentSystemDateTime.GetTime() >
sc.BaseDateTimeIn[as].GetTime() + sc.SecondsPerBar + 15) {
oC[op] = C[as];
}
oV[op] = V[as]; oT[op] = T[as];
}

// then look at live data
if (ts >= 0 && TSArray[ts].Sequence > seqno) {
int tp = ts;
int adjt = sc.TimeScaleAdjustment.GetTime();
double adj = sc.TimeScaleAdjustment;
while (TSArray[tp].Sequence > seqno) {tp--;}
// iterate through each time & sales value
for ( ; tp <= ts; tp++) {
// if its a new bar start one
if (tnsno == 0 && TSArray[tp].DateTime.GetTime() + adjt >=
sc.DateTimeOut[os].GetTime() + sc.SecondsPerBar) {
tnsno = 1; // flag that a time&sales bar has been created
os++;
sc.AddElements(1);
sc.DateTimeOut[os].SetDate(sc.DateTimeOut[as].GetDate());
sc.DateTimeOut[os].SetTime(sc.DateTimeOut[as].GetTime() +
sc.SecondsPerBar);
// note that for new session this bar time is wrong
// and it will be cancelled as spurious so the new bar
// will be formed when the first 5 sec bar arrives
oO[os] = oH[os] = oL[os] = oC[os] = TSArray[tp].Price;
oV[os] = TSArray[tp].Volume;
}
// else update high low and close for this bar
else if (TSArray[tp].DateTime.GetTime() + adjt >=
sc.DateTimeOut[os].GetTime() &&
TSArray[tp].DateTime.GetTime() + adjt <
sc.DateTimeOut[os].GetTime() + sc.SecondsPerBar) {
oH[os] = max(TSArray[tp].Price, oH[os]);
if (TSArray[tp].Price > 0 && oL[os] > 0)
oL[os] = min(TSArray[tp].Price, oL[os]);
else
oL[os] = max(TSArray[tp].Price, oL[os]);
oC[os] = TSArray[tp].Price;
}
}
seqno = TSArray[ts].Sequence;
}
// Check for spurious time & sales based bars (> 10 seconds with no 5sec)
if(tnsno != 0) {
// spurious if no 5 second confirmation within 15 seconds
if(sc.CurrentSystemDateTime.GetDate() > sc.DateTimeOut[os].GetDate() ||
sc.CurrentSystemDateTime.GetTime() > sc.DateTimeOut[os].GetTime()
+ 15) {
sc.AddElements(-1);
tnsno = 0;
}
}

sc.Subgraph[SC_HL][os] = (oH[os] + oL[os]) / 2;
sc.Subgraph[SC_HLC][os] = (oH[os] + oL[os] + oC[os]) / 3;
sc.Subgraph[SC_OHLC][os] = (oH[os] + oL[os] + oC[os] + oO[os]) / 4;
sc.Subgraph[SC_HL][op] = (oH[op] + oL[op]) / 2;
sc.Subgraph[SC_HLC][op] = (oH[op] + oL[op] + oC[op]) / 3;
sc.Subgraph[SC_OHLC][op] = (oH[op] + oL[op] + oC[op] + oO[op]) / 4;
}

Date Time Of Last Edit: 2014-06-30 05:47:08
attachmentkiwi14.cpp - Attached On 2014-06-30 05:45:46 UTC - Size: 15.89 KB - 527 views
attachmentkiwi14.dll - Attached On 2014-06-30 05:46:31 UTC - Size: 160.5 KB - 482 views
[2014-12-08 02:58:21]
User148364 - Posts: 4
Hi Kiwi, thanks as always for providing this custom study to the community. I used to use TrueLive back with the -TD charts and it worked great. I'm giving SierraCharts another go, and I haven't been able to get this new TrueLive version to work. I followed all of your instructions, but after I add it to the chart, the last price box on the price axis stops moving (only moves after new bar creation, depending on bar period). If I add a time and sales study to the chart, I can see that the chart continues to receive time and sales data, but the study is not updating the bars at all.

Are you still able to use this study? Any thoughts or suggestions? Thanks!

Mike
Date Time Of Last Edit: 2014-12-08 02:58:59
[2014-12-08 06:55:19]
Kiwi - Posts: 374
Hi Mike,

I just downloaded this dll myself.

I checked that file data trade service settings >> record true real time was set to True.

Then I opened EUR.USD-CASH-IDEALPRO.scid ... and checked that price only moved every 5 seconds but that the last price box was moving more often. Yep.

Then added kiwi14's TrueLive 2014 and changed the colors to something darker so I could see it.

And it worked .... the price box moved and the prices keep up with it.

One thought ... what version of SC are you using. Perhaps (use EUR so I can do the same as you ... you could record exactly what you do and also what happens with a picture.

Better thought (assuming study collections can be swapped between users still) ... here's my study collection with just that ...

Also heres a picture with Eur 1m on Athens time ... http://i.imgur.com/Nlk26cm.png

Also a pic of my ib settings just in case there's a clue ... http://i.imgur.com/lRiKzrZ.png
Date Time Of Last Edit: 2014-12-08 06:59:24
attachmentJustTrueLive.StdyCollct - Attached On 2014-12-08 06:54:05 UTC - Size: 9.39 KB - 479 views
[2014-12-08 12:46:00]
User148364 - Posts: 4
Kiwi - Great news, I replicated your IB settings, tried it with EUR and it worked perfect. Then I loaded a CL chart and it also worked. Still didn't work on my HHI.HK chart, so I recreated the chart and then it seems to have started working. The settings I changed in IB were the intraday data storage time (was previously 1 tick) and the Clear Out of Order Market Depth Data, which may have been the culprit (although I can't say I understand what that setting does). I'm still not convinced HHI is working 100% yet, seems a little slow/behind/out of sync with IB's booktrader, but it's outside RTH so I will take another look tonight when the market is actually moving. Thanks again!

Mike


[2014-12-09 01:58:25]
User148364 - Posts: 4
So after messing around quite a bit more, it seems the study is dependent on the data service time zone being set to Athens. When I have it set to my local time zone (US Central / Chicago) the study stops working and the charts freeze. Any idea why this would be? I don't see anything obvious in the code that would make this a requirement. Thanks again Kiwi.

Mike
[2014-12-17 00:49:57]
Kiwi - Posts: 374
I'll have a think about that. Not sure why it should be as my time is set to brisbane, australia.

Put your time for the market to 00:00 to 23:59 though ... just to make sure you aren't losing sight of your daily data ... also maybe set to allow data at all times not just RTH.

Does that make a difference?
[2014-12-17 05:02:21]
User148364 - Posts: 4
I can give more details now that I've been using it for a few days. I'm in the US, central time zone, but I trade off IB's Hong Kong servers because I primarily trade Asian products in the US evening, so that's where the data is coming from. In the evening, to get TrueLive 2014 to work, I have to set my Data/Trade Service Settings time zone to a non-US based time zone (I'm currently using Hong Kong instead of Athens), otherwise the charts freeze and there's no movement. However, during the US daytime, to get Truelive to work, I have to change the time zone back to a US zone (i.e. Chicago). I haven't tried every time zone option during each period to isolate which ones work and which don't. I'm guessing throughout the day there's a moving line/zone that travels with the sun that if crossed over TrueLive stops working, but maybe there's just a hard cutoff based on a server reset time or something.

Anyway, maybe that's a clue into this strange behavior. It works well enough for now, so I'm not worried about it, but at least the issue is repeatable so there has to be an explanation.

Mike

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

Login

Login Page - Create Account