Login Page - Create Account

Support Board


Date/Time: Tue, 30 Apr 2024 00:02:21 +0000



Orderflowanalytics-style reversal bars.

View Count: 30966

[2013-09-13 23:45:49]
marcovth - Posts: 61
Hello ...

I have been watching this particular Orderflowanalytics video which gives a clue about the type of custom made reversal bars they are using.
www.screencast.com/users/OFANinjaLibrary/folders/OFAFREE/media/53c943cc-beaf-4e2f-825c-ee68cb011578

He speaks about at least an 8 tick directional move (I assume 8+ ticks from Low to High or High to low) and then a 4 tick reversal before a new bar is printed.

Of course they can change these settings.

I have been testing all the bars in SC (including the reversal bar and PnF bars) but non of them look the same.

The closest bar type I have seen is Better Renko, written by "aslan"?

Since there is no private message system, I will ask all of you:
Is there some one who can help me to modify the Better Renko code so that you can set the directional move distance and reversal size?

I have tried to change some of the code, but it all became messed up.

Thanks in advance.


//
// BetterRenko
//
// written by aslan
//
// 20101215 - initial version for SC
// 20110111 - fixed OHLC averages, removed showWicks to allow other bar types
//
#include "sierrachart.h"

SCDLLName("BetterRenko")


inline void br_MoveLimits(SCStudyGraphRef sc, float high, float low, float brickSize, int revMult, float& renkoHigh, float& renkoLow)
{
  if (sc.FormattedEvaluate(high, sc.ValueFormat, GREATER_EQUAL_OPERATOR, renkoHigh, sc.ValueFormat))
  {
    do
    {
      renkoHigh += brickSize;
      renkoLow = renkoHigh - ((revMult+1) * brickSize);
    } while (sc.FormattedEvaluate(high, sc.ValueFormat, GREATER_OPERATOR, renkoHigh, sc.ValueFormat)); // stops if price in range, including edge
  }
  else
  {
    do
    {
      renkoLow -= brickSize;
      renkoHigh = renkoLow + ((revMult+1) * brickSize);
    } while (sc.FormattedEvaluate(low, sc.ValueFormat, LESS_OPERATOR, renkoLow, sc.ValueFormat));
  }
}

inline void br_CheckBarComplete(SCStudyGraphRef sc, float high, float low, float brickSize, int revMult, float& renkoHigh, float& renkoLow, int& barComplete)
{
  if (sc.FormattedEvaluate(high, sc.ValueFormat, EQUAL_OPERATOR, renkoHigh, sc.ValueFormat) ||
    sc.FormattedEvaluate(low, sc.ValueFormat, EQUAL_OPERATOR, renkoLow, sc.ValueFormat))
  {
    barComplete = true;
    br_MoveLimits(sc, high, low, brickSize, revMult, renkoHigh, renkoLow); // will move limits once since equal
  }
  else barComplete = false;
}

inline bool br_RangeExceeded(SCStudyGraphRef sc, float high, float low, float& renkoHigh, float& renkoLow)
{
  return   sc.FormattedEvaluate(high, sc.ValueFormat, GREATER_OPERATOR, renkoHigh, sc.ValueFormat) ||
      sc.FormattedEvaluate(low, sc.ValueFormat, LESS_OPERATOR, renkoLow, sc.ValueFormat);
}


// macros for bar creation/updates, handles tick or bar inputs
#define UPDATE_OPENS()                    \
  /* set renkoOpen based on brick size and price action */\
  if (Close[o] > Open[o])                  \
    RenkoOpen[o] = max(Close[o] - brickSize, Low[o]);  \
  else                          \
    RenkoOpen[o] = min(Close[o] + brickSize, High[o]);  \
                              \
  /* adjust open to show RenkoOpen instead of real open */\
  if (showRealOpen.GetYesNo() == 0)            \
  {                            \
    float temp = Open[o];                \
    Open[o] = RenkoOpen[o];                \
    RenkoOpen[o] = temp;                \
  }                            \

#define ADD_BAR()                      \
  sc.AddElements(1);                    \
  o++;                          \
  sc.DateTimeOut[o] = sc.BaseDateTimeIn[i];        \
  Open[o] = iOpen[i];                    \
  High[o] = iHigh[i];                    \
  Low[o] = iLow[i];                    \
  Close[o] = iClose[i];                  \
  Volume[o] = iVolume[i];                  \
  Ticks[o] = iTicks[i];                  \
  sc.CalculateOHLCAverages(o);              \
  BidVol[o] = iBidVol[i];                  \
  AskVol[o] = iAskVol[i];                  \
  UpTickVol[o] = iUpTickVol[i];              \
  DownTickVol[o] = iDownTickVol[i];            \
  BidTrades[o] = iBidTrades[i];              \
  AskTrades[o] = iAskTrades[i];              \
  RenkoOpen[o] = iOpen[i]

#define UPDATE_BAR()                    \
  if (iHigh[i] > High[o]) High[o] = iHigh[i];        \
  if (iLow[i] < Low[o]) Low[o] = iLow[i];        \
  Close[o] = iClose[i];                  \
  Volume[o] += iVolume[i];                \
  Ticks[o] += iTicks[i];                  \
  sc.CalculateOHLCAverages(o);              \
  BidVol[o] += iBidVol[i];                \
  AskVol[o] += iAskVol[i];                \
  UpTickVol[o] += iUpTickVol[i];              \
  DownTickVol[o] += iDownTickVol[i];            \
  BidTrades[o] += iBidTrades[i];              \
  AskTrades[o] += iAskTrades[i];              \
  RenkoOpen[o] = iClose[i]


SCSFExport scsf_BetterRenko(SCStudyGraphRef sc)
{
  // input refs
  SCInputRef brickSizeTicks = sc.Input[0];
  SCInputRef alignToBrickSize = sc.Input[1];
  SCInputRef showRealOpen = sc.Input[2];
  SCInputRef reverseMultiplier = sc.Input[3];

  // input bar refs
  SCFloatArrayRef iOpen = sc.BaseDataIn[0];
  SCFloatArrayRef iHigh = sc.BaseDataIn[1];
  SCFloatArrayRef iLow = sc.BaseDataIn[2];
  SCFloatArrayRef iClose = sc.BaseDataIn[3];
  SCFloatArrayRef iVolume = sc.BaseDataIn[4];
  SCFloatArrayRef iTicks = sc.BaseDataIn[5];
  SCFloatArrayRef iBidVol = sc.BaseDataIn[9];
  SCFloatArrayRef iAskVol = sc.BaseDataIn[10];
  SCFloatArrayRef iUpTickVol = sc.BaseDataIn[11];
  SCFloatArrayRef iDownTickVol = sc.BaseDataIn[12];
  SCFloatArrayRef iBidTrades = sc.BaseDataIn[13];
  SCFloatArrayRef iAskTrades = sc.BaseDataIn[14];

  // ouput bar refs
  SCSubgraphRef Open = sc.Subgraph[0];
  SCSubgraphRef High = sc.Subgraph[1];
  SCSubgraphRef Low = sc.Subgraph[2];
  SCSubgraphRef Close = sc.Subgraph[3];
  SCSubgraphRef Volume = sc.Subgraph[4];
  SCSubgraphRef Ticks = sc.Subgraph[5];
  SCSubgraphRef OHLCAvg = sc.Subgraph[6];
  SCSubgraphRef HLCAvg = sc.Subgraph[7];
  SCSubgraphRef HLAvg = sc.Subgraph[8];
  SCSubgraphRef BidVol = sc.Subgraph[9];
  SCSubgraphRef AskVol = sc.Subgraph[10];
  SCSubgraphRef UpTickVol = sc.Subgraph[11];
  SCSubgraphRef DownTickVol = sc.Subgraph[12];
  SCSubgraphRef BidTrades = sc.Subgraph[13];
  SCSubgraphRef AskTrades = sc.Subgraph[14];
  SCSubgraphRef RenkoOpen = sc.Subgraph[15]; // Renko Open or True Open based on input value


  // Set configuration variables
  if (sc.SetDefaults)
  {
    // Set the defaults
    sc.GraphName = "BetterRenko";
    sc.StudyDescription = "BetterRenko custom chart.";
    
    sc.IsCustomChart = 1;
    sc.DisplayAsMainPriceGraph = 1;
    sc.GraphRegion = 0;
    sc.StandardChartHeader = 1;
    sc.DrawZeros = 0;
    sc.GraphDrawType = GDT_CANDLESTICK;
    sc.AutoLoop = 0;
    sc.FreeDLL = 1;

    sc.ValueFormat = sc.BaseGraphValueFormat;

    // Inputs    
    brickSizeTicks.Name = "Brick size (ticks):";
    brickSizeTicks.SetInt(4);
    alignToBrickSize.Name = "Align to brick size:";
    alignToBrickSize.SetYesNo(1);
    showRealOpen.Name = "Show real Open (vs Renko Open):";
    showRealOpen.SetYesNo(0);
    reverseMultiplier.Name = "Reverse multiplier (number of bricks):";
    reverseMultiplier.SetInt(2);
    reverseMultiplier.SetIntLimits(1, 20);

    // Subgraphs
    Open.Name = "Open";
    Open.DrawStyle = DRAWSTYLE_LINE;
    Open.PrimaryColor = RGB(0,200,0);
    
    High.Name = "High";
    High.DrawStyle = DRAWSTYLE_LINE;
    High.PrimaryColor = RGB(0,0,0);
    
    Low.Name = "Low";
    Low.DrawStyle = DRAWSTYLE_LINE;
    Low.PrimaryColor = RGB(200,0,0);
    
    Close.Name = "Close";
    Close.DrawStyle = DRAWSTYLE_LINE;
    Close.PrimaryColor = RGB(0,0,0);

    Volume.Name = "Volume";
    Volume.DrawStyle = DRAWSTYLE_IGNORE;
    Ticks.Name = "# of Trades";
    Ticks.DrawStyle = DRAWSTYLE_IGNORE;

    OHLCAvg.Name = "OHLC Avg";
    OHLCAvg.DrawStyle = DRAWSTYLE_IGNORE;
    HLCAvg.Name = "HLC Avg";
    HLCAvg.DrawStyle = DRAWSTYLE_IGNORE;
    HLAvg.Name = "HL Avg";
    HLAvg.DrawStyle = DRAWSTYLE_IGNORE;

    BidVol.Name = "Bid Vol";
    BidVol.DrawStyle = DRAWSTYLE_IGNORE;
    AskVol.Name = "Ask Vol";
    AskVol.DrawStyle = DRAWSTYLE_IGNORE;

    UpTickVol.Name = "Up Tick Vol";
    UpTickVol.DrawStyle = DRAWSTYLE_IGNORE;
    DownTickVol.Name = "Down Tick Vol";
    DownTickVol.DrawStyle = DRAWSTYLE_IGNORE;

    BidTrades.Name = "Bid Trades";
    BidTrades.DrawStyle = DRAWSTYLE_IGNORE;
    AskTrades.Name = "Ask Trades";
    AskTrades.DrawStyle = DRAWSTYLE_IGNORE;

    RenkoOpen.Name = "Renko/True Open";
    RenkoOpen.DrawStyle = DRAWSTYLE_IGNORE;

    return;
  }

  //try
  //{
    long i = 0;    // input index - underlying chart
    long o = 0;    // output index - renko chart
    float cum = 0; // calc cumulative delta

    // refs to persistent vars
    float& brickSize = sc.PersistVars->f1; // brickSize in terms of price
    float& renkoHigh = sc.PersistVars->f2; // renkoHigh
    float& renkoLow = sc.PersistVars->f3; // renkoLow
    int& lastIndex = sc.PersistVars->i1; // lastIndex processed
    int& barComplete = sc.PersistVars->i2; // barComplete

    if (sc.UpdateStartIndex == 0)
    {
      // clear existing chart data
      sc.ResizeArrays(0);

      // init state i.e. persist vars
      brickSize = sc.RoundToTickSize(brickSizeTicks.GetInt() * sc.TickSize, sc.TickSize);
      lastIndex = -1;
      barComplete = false;

      sc.ValueFormat = sc.BaseGraphValueFormat;
      sc.GraphName.Format("BetterRenko %i", brickSizeTicks.GetInt());

      RenkoOpen.Name = showRealOpen.GetYesNo() ? "True Open" : "Renko Open";
    }

    // do data processing
    o = sc.OutArraySize - 1;


    for (int i = sc.UpdateStartIndex; i < sc.ArraySize; i++)
    {
      if (i == lastIndex) continue; // block handling the same tick multiple times

      // starting new bar at session boundary makes sure you have the same bars
      // reguardless of the first date that is loaded in the chart
      // Note: using date change instead of session boundary
      if (i == 0 || (sc.BaseDateTimeIn[i-1].GetDate() != sc.BaseDateTimeIn[i].GetDate()))
      {
        // create new bar
        if (i != 0) {
          UPDATE_OPENS();
        }
        ADD_BAR();
        float mod = !alignToBrickSize.GetYesNo() ? brickSize : sc.RoundToTickSize(fmod(Close[o], brickSize), sc.TickSize);
        float mid = sc.FormattedEvaluate(mod, sc.ValueFormat, EQUAL_OPERATOR, brickSize, sc.ValueFormat) ? Close[o] : Close[o] - mod;
        renkoHigh = mid + brickSize;
        renkoLow = mid - brickSize;
        barComplete = false;
      }
      else
      {
        if (barComplete)
        {
          // this tick creates a new bar
          UPDATE_OPENS();
          ADD_BAR();
          if (br_RangeExceeded(sc, High[o], Low[o], renkoHigh, renkoLow))
            br_MoveLimits(sc, High[o], Low[o], brickSize, reverseMultiplier.GetInt(), renkoHigh, renkoLow);
        }
        else
        {
          if (br_RangeExceeded(sc, iHigh[i], iLow[i], renkoHigh, renkoLow))
          {
            UPDATE_OPENS();
            ADD_BAR();
            br_MoveLimits(sc, High[o], Low[o], brickSize, reverseMultiplier.GetInt(), renkoHigh, renkoLow);
          }
          else
          {
            UPDATE_BAR();
          }
        }
        br_CheckBarComplete(sc, High[o], Low[o], brickSize, reverseMultiplier.GetInt(), renkoHigh, renkoLow, barComplete);
      }
      lastIndex = i;
    }
  //}
  //catch (char *ErrMsg){
  //  sc.AddMessageToLog(ErrMsg, 1);
  //}
}



[2013-09-14 00:42:01]
marcovth - Posts: 61
Here is a previous attempt I wrote, but something is missing.

It seems to work, but it's messing up other studies that I add to the chart (which is not the case with the Better Renko or PnF studies.

So if you can detect what's wrong, that would be helpful too.


#include "sierrachart.h"

SCDLLName("DirectionalReversalChart")

SCSFExport scsf_CopyOfBaseGraph(SCStudyInterfaceRef sc){

  SCSubgraphRef Open = sc.Subgraph[0];
  SCSubgraphRef High = sc.Subgraph[1];
  SCSubgraphRef Low = sc.Subgraph[2];
  SCSubgraphRef Close = sc.Subgraph[3];
  SCSubgraphRef Volume = sc.Subgraph[4];
  SCSubgraphRef OpenInterest = sc.Subgraph[5];
  SCSubgraphRef OHLCAvg = sc.Subgraph[6];
  SCSubgraphRef HLCAvg = sc.Subgraph[7];
  SCSubgraphRef HLAvg = sc.Subgraph[8];
  SCSubgraphRef BidVol = sc.Subgraph[9];
  SCSubgraphRef AskVol = sc.Subgraph[10];

  if (sc.SetDefaults){

    sc.GraphName = "Directional Reversal Chart";
    sc.StudyDescription = "";

    sc.IsCustomChart = 1;
    sc.GraphRegion = 0;    
    sc.DrawZeros = 0;
    sc.GraphDrawType = GDT_CANDLESTICK;
    sc.StandardChartHeader = 1;
    sc.DisplayAsMainPriceGraph = 1;
    sc.ValueFormat = sc.BaseGraphValueFormat;

    Open.Name = "Open";
    Open.DrawStyle = DRAWSTYLE_LINE;
    Open.PrimaryColor = RGB(0,200,0);
    
    High.Name = "High";
    High.DrawStyle = DRAWSTYLE_LINE;
    High.PrimaryColor = RGB(0,0,0);

    Low.Name = "Low";
    Low.DrawStyle = DRAWSTYLE_LINE;
    Low.PrimaryColor = RGB(200,0,0);

    Close.Name = "Close";
    Close.DrawStyle = DRAWSTYLE_LINE;
    Close.PrimaryColor = RGB(0,0,0);

    Volume.Name = "Volume";
    Volume.DrawStyle = DRAWSTYLE_IGNORE;

    OpenInterest.Name = "# of Trades / OI";
    OpenInterest.DrawStyle = DRAWSTYLE_IGNORE;

    OHLCAvg.Name = "OHLC Avg";
    OHLCAvg.DrawStyle = DRAWSTYLE_IGNORE;

    HLCAvg.Name = "HLC Avg";
    HLCAvg.DrawStyle = DRAWSTYLE_IGNORE;

    HLAvg.Name = "HL Avg";
    HLAvg.DrawStyle = DRAWSTYLE_IGNORE;

    BidVol.Name = "Bid Vol";
    BidVol.DrawStyle = DRAWSTYLE_IGNORE;

    AskVol.Name = "Ask Vol";
    AskVol.DrawStyle = DRAWSTYLE_IGNORE;
    
    sc.FreeDLL = 1;
    sc.AutoLoop = 1;
    sc.MaintainVolumeAtPriceData = 1;
    
    return;
  }
  
  int i=sc.Index;
  SCString message;
  
  // If our start index is zero, then we want to clear our existing chart
  // data, if any, so we start clean to avoid any possible problems. This
  // is accomplished by using sc.ResizeArrays.
  if (sc.UpdateStartIndex == 0) sc.ResizeArrays(0);
  
  unsigned int AskVolume    = 0;
  unsigned int BidVolume  = 0;
  float Price=0;
  float prevPrice=0;
  
  float& DirectionalMove = sc.PersistVars->f1;
  //float& OpenBar = sc.PersistVars->f2;
  //float& HighBar = sc.PersistVars->f3;
  //float& LowBar = sc.PersistVars->f4;
  
  
  if( i==sc.ArraySize-2 || (i > sc.ArraySize-2) ){ // && sc.GetBarHasClosedStatus(i) == BHCS_BAR_HAS_CLOSED
    sc.ResizeArrays(0);
    //HighBar=0;
    //LowBar=0;
    //OpenBar=0;
    int prevIndex=0;
    int out=-1;
    //for (int n = sc.UpdateStartIndex; n < sc.ArraySize; n++){
    for (int n = 0; n < sc.ArraySize; n++){
  
      if(n==0){
        //HighBar=sc.High[n];
        //LowBar=sc.Low[n];
        //OpenBar=sc.Open[n];
      } else {
      
        float HighBar=sc.GetHighest(sc.High,n,n-prevIndex);
        float LowBar=sc.GetLowest(sc.Low,n,n-prevIndex);
        float OpenBar=sc.Open[prevIndex+1];
        
        if(sc.High[n]>0 and sc.High[n]>HighBar)HighBar=sc.High[n];
        if(sc.Low[n]>0 and sc.Low[n]<LowBar) LowBar=sc.Low[n];
        
        bool PrintBar=false;
        if(sc.Close[n]>0 and (HighBar-LowBar)>(8.0f*sc.TickSize) ){
          if( (HighBar-sc.Close[n])>=(4.0f*sc.TickSize) or (sc.Close[n]-LowBar)>=(4.0f*sc.TickSize) ){
            // 8 tick directional move with 4 tick pullback
            PrintBar=true;
          }
        }


        if(PrintBar){
          //if (sc.OutArraySize-1 < n)
          sc.AddElements(1);
          out++;
          High[out]=HighBar;
          Low[out]=LowBar;
          Open[out]=OpenBar;
          Close[out]=sc.Close[n];
          //HighBar=sc.High[n];
          //LowBar=sc.Low[n];
          //OpenBar=sc.Close[n];
          prevIndex=n;
          //message.Format("%f | %f | %f | %f",OpenBar,HighBar,LowBar,Price);
          //sc.AddMessageToLog(message, 1);
          
          
          sc.DateTimeOut[out] = sc.BaseDateTimeIn[n];
          /*for (int SubGraph = 0; SubGraph <=10; SubGraph++){
            sc.Subgraph[SubGraph][n] = sc.BaseDataIn[SubGraph][n];

            //For testing coloring bars
            //sc.Subgraph[SubGraph].DataColor[i] = RGB(255,255,255);
          }*/
          PrintBar=false;
        }
      }
    }
  }
}




[2014-01-12 08:51:42]
User42019 - Posts: 6
Hi,
Is there any follow up to your efforts?
[2014-01-23 17:20:42]
norvik_ - Posts: 106
I had modified code of P&F Bars from ASC_Source folder. It seems works correct.
#include "C:\SierraChart\ACS_Source\sierrachart.h"

SCDLLName("OFAChart")


SCSFExport scsf_OFAChart(SCStudyInterfaceRef sc)
{
SCSubgraphRef Open = sc.Subgraph[SC_OPEN];
SCSubgraphRef High = sc.Subgraph[SC_HIGH];
SCSubgraphRef Low = sc.Subgraph[SC_LOW];
SCSubgraphRef Last = sc.Subgraph[SC_LAST];
SCSubgraphRef Volume = sc.Subgraph[SC_VOLUME];
SCSubgraphRef NumTrades = sc.Subgraph[SC_NT];
SCSubgraphRef OHLCAvg = sc.Subgraph[SC_OHLC];
SCSubgraphRef HLCAvg = sc.Subgraph[SC_HLC];
SCSubgraphRef HLAvg = sc.Subgraph[SC_HL];
SCSubgraphRef BidVol = sc.Subgraph[SC_BIDVOL];
SCSubgraphRef AskVol = sc.Subgraph[SC_ASKVOL];
SCSubgraphRef UpTickVol = sc.Subgraph[SC_UPVOL];
SCSubgraphRef DownTickVol = sc.Subgraph[SC_DOWNVOL];
SCSubgraphRef BidTrades = sc.Subgraph[SC_BIDNT];
SCSubgraphRef AskTrades = sc.Subgraph[SC_ASKNT];
SCSubgraphRef BidAskDiffMax = sc.Subgraph[SC_ASKBID_DIFF_HIGH];
SCSubgraphRef BidAskDiffMin = sc.Subgraph[SC_ASKBID_DIFF_LOW];
SCSubgraphRef NumberOfBoxes = sc.Subgraph[PF_NUM_BOXES_ARRAY];
SCSubgraphRef DirectionArray = sc.Subgraph[PF_DIRECTION_ARRAY];
SCSubgraphRef TrueLast = sc.Subgraph[PF_TRUELAST_ARRAY];

const int ArrayCount = PF_TRUELAST_ARRAY + 1;

    SCInputRef InitialRangeTicks = sc.Input[0];
SCInputRef ReversalSize = sc.Input[1];
SCInputRef AllowOneBoxReversals = sc.Input[2];
SCInputRef NewBarAtStartOfDay = sc.Input[3];
SCInputRef IgnoreLastBarUntilComplete = sc.Input[4];

if (sc.SetDefaults)
{
sc.GraphName = "OFA Chart";

sc.GraphRegion = 0;
sc.StandardChartHeader = 1;
sc.IsCustomChart = 1;
sc.GraphDrawType = GDT_CANDLESTICK;
sc.DrawZeros = 0;
sc.FreeDLL = 1;

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

High.Name = "High";
High.DrawStyle = DRAWSTYLE_LINE;

High.PrimaryColor = RGB(0,255,0);

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

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

Volume.Name = "Volume";
Volume.DrawStyle = DRAWSTYLE_IGNORE;
Volume.PrimaryColor = RGB(255,255,255);

NumTrades.Name = "# of Trades / OI";
NumTrades.DrawStyle = DRAWSTYLE_IGNORE;
NumTrades.PrimaryColor = RGB(255,255,255);

OHLCAvg.Name = "OHLC Avg";
OHLCAvg.DrawStyle = DRAWSTYLE_IGNORE;
OHLCAvg.PrimaryColor = RGB(255,255,255);

HLCAvg.Name = "HLC Avg";
HLCAvg.DrawStyle = DRAWSTYLE_IGNORE;
HLCAvg.PrimaryColor = RGB(255,255,255);

HLAvg.Name = "HL Avg";
HLAvg.DrawStyle = DRAWSTYLE_IGNORE;
HLAvg.PrimaryColor = RGB(255,255,255);

BidVol.Name = "Bid Vol";
BidVol.DrawStyle = DRAWSTYLE_IGNORE;
BidVol.PrimaryColor = RGB(255,255,255);

AskVol.Name = "Ask Vol";
AskVol.DrawStyle = DRAWSTYLE_IGNORE;
AskVol.PrimaryColor = RGB(255,255,255);

NumberOfBoxes.Name = "Number of Boxes";
NumberOfBoxes.DrawStyle = DRAWSTYLE_IGNORE;
NumberOfBoxes.PrimaryColor = RGB(0xFF,0x99,0x00);

TrueLast.Name = "True Last";
TrueLast.DrawStyle = DRAWSTYLE_IGNORE;
TrueLast.PrimaryColor = RGB(255,255,255);

InitialRangeTicks.Name = "Target range (ticks):";
          InitialRangeTicks.SetInt(6);

ReversalSize.Name = "Reversal Size";
ReversalSize.SetFloat(3.0f);
ReversalSize.SetFloatLimits(FLT_MIN, FLT_MAX);

AllowOneBoxReversals.Name = "Allow One Box Reversals";

AllowOneBoxReversals.SetYesNo(1);

NewBarAtStartOfDay.Name = "New Bar at Start of Day";
NewBarAtStartOfDay.SetYesNo(0);

IgnoreLastBarUntilComplete.Name = "Ignore Last Bar Until Completed";
IgnoreLastBarUntilComplete.SetYesNo(0);

return;
}


struct s_PFStorage
{
int PriorOutArraySize;
float PriorOutData[ArrayCount];
float High;
float Low;
int Index;
float targetRange;
};

s_PFStorage* p_PFStorage = (s_PFStorage*)sc.StorageBlock;

SCDateTime& NextSessionStart = sc.PersistVars->scdt1;

int InputIndex = sc.UpdateStartIndex;
int AvgStartIndex = 0;

if (InputIndex == 0)
{
sc.ResizeArrays(0);

AvgStartIndex = 0;

// Clear the last state data
memset(p_PFStorage, 0, sizeof(p_PFStorage));

p_PFStorage->Index = -1;
p_PFStorage->targetRange = sc.RoundToTickSize(InitialRangeTicks.GetInt() * sc.TickSize, sc.TickSize);

if (!sc.AddElements(1))
return;

sc.DateTimeOut[0] = sc.BaseDateTimeIn[0];

Open[0] = sc.Open[0];
High[0] = sc.Close[0];

Low[0] = sc.Close[0];

Last[0] = sc.Close[0];
TrueLast[0] = sc.Close[0];

NextSessionStart = sc.GetTradingDayStartDateTimeOfBar(sc.BaseDateTimeIn[0]) + 1*DAYS;


NumTrades.Name = "# of Trades";

sc.GraphName.Format("OFAChart %.6gx%g %s",ReversalSize.GetFloat(),sc.GetStudyNameFromChart(sc.ChartNumber, 0).GetChars());
}

else if (!IgnoreLastBarUntilComplete.GetYesNo())
{
AvgStartIndex = p_PFStorage->PriorOutArraySize - 1;

// Restore array to size just before processing last input bar (sc.BaseDataIn) and restore state of last output bar.

sc.ResizeArrays(p_PFStorage->PriorOutArraySize);

for (int SubgraphIndex = 0; SubgraphIndex < ArrayCount; ++SubgraphIndex)
{
sc.Subgraph[SubgraphIndex][AvgStartIndex] = p_PFStorage->PriorOutData[SubgraphIndex];
}

}

int OutputIndex = sc.DateTimeOut.GetArraySize() - 1;
if (InputIndex == 0)
InputIndex = 1;

for (; InputIndex < sc.ArraySize; ++InputIndex)
{
bool NewBar = false;

if (IgnoreLastBarUntilComplete.GetYesNo() && sc.GetBarHasClosedStatus(InputIndex)== BHCS_BAR_HAS_NOT_CLOSED)
return;

if (NewBarAtStartOfDay.GetYesNo() != 0)
{
SCDateTime IndexDateTime = sc.BaseDateTimeIn[InputIndex];

if (IndexDateTime >= NextSessionStart)
{
sc.CalculateOHLCAverages(OutputIndex);

if (!sc.AddElements(1))
return;

NewBar = true;
OutputIndex = sc.DateTimeOut.GetArraySize() - 1;

sc.DateTimeOut[OutputIndex] = sc.BaseDateTimeIn[InputIndex];

Open[OutputIndex] = sc.Open[InputIndex];
High[OutputIndex] = sc.Close[InputIndex];
Low[OutputIndex] = sc.Close[InputIndex];
Last[OutputIndex] = sc.Close[InputIndex];
TrueLast[OutputIndex] = sc.Close[InputIndex];

NextSessionStart = sc.GetTradingDayStartDateTimeOfBar(IndexDateTime) + 1*DAYS;
}
}

// Remember state of last P&F bar when reach last input bar because last
// input bar can change due to updating, causing for example a new P&F bar
// to be added when on a later update no new bar is added.
if (!IgnoreLastBarUntilComplete.GetYesNo() && InputIndex == sc.ArraySize - 1)
{
p_PFStorage->PriorOutArraySize = OutputIndex + 1;
for (int SubgraphIndex = 0; SubgraphIndex < ArrayCount; ++SubgraphIndex)
{
p_PFStorage->PriorOutData[SubgraphIndex] = sc.Subgraph[SubgraphIndex][OutputIndex];
}
}
          
// Determine our initial direction if not known
if (DirectionArray[OutputIndex] == 0.0f)
{
if (Last[OutputIndex] > sc.Close[InputIndex])
DirectionArray[OutputIndex] = -1; // Down

else if (Last[OutputIndex] < sc.Close[InputIndex])
DirectionArray[OutputIndex] = 1; // Up
}

if (DirectionArray[OutputIndex] == 0.0f)
continue; // No direction


bool UseHighFirst;

int OpenToHighLow = sc.CompareOpenToHighLow(sc.Open[InputIndex],sc.High[InputIndex], sc.Low[InputIndex], sc.BaseGraphValueFormat);

if(OpenToHighLow == 1)
UseHighFirst = true;
else if(OpenToHighLow == -1)
UseHighFirst = false;
else if (sc.FormattedEvaluate(sc.Open[InputIndex] , sc.BaseGraphValueFormat,GREATER_OPERATOR, sc.Close[InputIndex], sc.BaseGraphValueFormat))
UseHighFirst = true;
else if (sc.FormattedEvaluate(sc.Open[InputIndex] , sc.BaseGraphValueFormat,LESS_OPERATOR, sc.Close[InputIndex], sc.BaseGraphValueFormat))
UseHighFirst = false;
else if (DirectionArray[OutputIndex] == 1) // Up Bar
UseHighFirst = true;
else
UseHighFirst = false;

for (int PassNumber=0; PassNumber<2; PassNumber++)
{
if (DirectionArray[OutputIndex] == 1)
{
if ((UseHighFirst && PassNumber == 0 ) || (!UseHighFirst &&PassNumber ==1))
{
if (sc.FormattedEvaluate(sc.High[InputIndex],sc.BaseGraphValueFormat, GREATER_EQUAL_OPERATOR, High[OutputIndex],sc.BaseGraphValueFormat))
{
High[OutputIndex] = sc.High[InputIndex];
}
}

if ((PassNumber == 0) || (UseHighFirst && PassNumber == 1))
{
  
                      float trueRange = High[OutputIndex] - Low[OutputIndex];

if ((sc.FormattedEvaluate(sc.Low[InputIndex],sc.BaseGraphValueFormat, LESS_EQUAL_OPERATOR, High[OutputIndex] - sc.TickSize *ReversalSize.GetFloat(), sc.BaseGraphValueFormat))&&(sc.FormattedEvaluate(trueRange, sc.ValueFormat, GREATER_OPERATOR, p_PFStorage->targetRange, sc.ValueFormat)))
{
Last[OutputIndex] = High[OutputIndex];

bool SetOpen = false;

if (AllowOneBoxReversals.GetYesNo())
{
// Calculate the number of boxes for the column
NumberOfBoxes[OutputIndex] =(float)sc.Round(High[OutputIndex] - Low[OutputIndex]);

sc.CalculateOHLCAverages(OutputIndex);

if (!sc.AddElements(1))
return;

NewBar = true;
OutputIndex++;
sc.DateTimeOut[OutputIndex] = sc.BaseDateTimeIn[InputIndex];

High[OutputIndex] = High[OutputIndex - 1];

SetOpen = true;
}

DirectionArray[OutputIndex] = -1;
Low[OutputIndex] = sc.Low[InputIndex];

if (SetOpen)
Open[OutputIndex] = Low[OutputIndex];

}
}

if (UseHighFirst)
PassNumber++;

}
else// down column
{
if ((!UseHighFirst && PassNumber == 0) || (UseHighFirst && PassNumber ==1))
{
if (sc.FormattedEvaluate(sc.Low[InputIndex] ,sc.BaseGraphValueFormat, LESS_EQUAL_OPERATOR, Low[OutputIndex] ,sc.BaseGraphValueFormat))
{

Low[OutputIndex] = sc.Low[InputIndex];
}
}

if (PassNumber == 0 || (!UseHighFirst && PassNumber == 1))
{
  
                      float trueRange = High[OutputIndex] - Low[OutputIndex];
  
if ((sc.FormattedEvaluate(sc.High[InputIndex] ,sc.BaseGraphValueFormat, GREATER_EQUAL_OPERATOR, Low[OutputIndex] + sc.TickSize *ReversalSize.GetFloat(), sc.BaseGraphValueFormat))&&(sc.FormattedEvaluate(trueRange, sc.ValueFormat, GREATER_OPERATOR, p_PFStorage->targetRange, sc.ValueFormat)))
{
Last[OutputIndex] = High[OutputIndex];

Last[OutputIndex] = Low[OutputIndex];

bool SetOpen = false;
if (AllowOneBoxReversals.GetYesNo())
{
// Calculate the number of boxes for the column
NumberOfBoxes[OutputIndex] = High[OutputIndex] - Low[OutputIndex];

sc.CalculateOHLCAverages(OutputIndex);

if (!sc.AddElements(1))
return;

NewBar = true;
OutputIndex++;
sc.DateTimeOut[OutputIndex] =sc.BaseDateTimeIn[InputIndex];

Low[OutputIndex] = Low[OutputIndex - 1];

SetOpen = true;
}

DirectionArray[OutputIndex] = 1;
High[OutputIndex] = sc.High[InputIndex];

if (SetOpen)
Open[OutputIndex] = High[OutputIndex];
}
}

if (!UseHighFirst)
PassNumber++;

}//else down column
} // PassNumber for loop

TrueLast[OutputIndex] = sc.Close[InputIndex];
Last[OutputIndex] = sc.Close[InputIndex];
sc.CalculateOHLCAverages(OutputIndex);

NumberOfBoxes[OutputIndex] = (float)sc.Round((High[OutputIndex] -Low[OutputIndex])/sc.TickSize);

// Add in volume and open interest
Volume[OutputIndex] += sc.Volume[InputIndex];
NumTrades[OutputIndex] += sc.OpenInterest[InputIndex];
float BidAskDiffHigh = 0;
float BidAskDiffLow = 0;
if (sc.BaseDataIn.GetArraySize() >= SC_ASKBID_DIFF_LOW+1)
{
BidAskDiffHigh = AskVol[OutputIndex] - BidVol[OutputIndex] +sc.BaseDataIn[SC_ASKBID_DIFF_HIGH][InputIndex];
BidAskDiffLow = AskVol[OutputIndex] - BidVol[OutputIndex] +sc.BaseDataIn[SC_ASKBID_DIFF_LOW][InputIndex];
}
BidVol[OutputIndex] += sc.BidVolume[InputIndex];
AskVol[OutputIndex] += sc.AskVolume[InputIndex];
UpTickVol[OutputIndex] += sc.UpTickVolume[InputIndex];
DownTickVol[OutputIndex] += sc.DownTickVolume[InputIndex];
BidTrades[OutputIndex] += sc.NumberOfBidTrades[InputIndex];
AskTrades[OutputIndex] += sc.NumberOfAskTrades[InputIndex];

if (NewBar || BidAskDiffHigh > BidAskDiffMax[OutputIndex])
BidAskDiffMax[OutputIndex] = BidAskDiffHigh;

if (NewBar || BidAskDiffLow < BidAskDiffMin[OutputIndex])
BidAskDiffMin[OutputIndex] = BidAskDiffLow;
}
}

Date Time Of Last Edit: 2014-01-23 17:23:07
[2014-01-23 18:49:13]
User42019 - Posts: 6
Thanks for your efforts.
Seems like still something has to be adjusted to match the original OFA bars...
Hopefully, you'll match...
[2014-01-24 17:41:58]
norvik - Posts: 22
Code in my previos post is not correct. Here is a new one, I hope without mistakes.
attachmentOFAChart.cpp - Attached On 2014-01-24 17:41:09 UTC - Size: 7.6 KB - 842 views
imageOFA.jpg / V - Attached On 2014-01-24 17:41:47 UTC - Size: 187.24 KB - 2709 views
[2014-01-25 08:13:21]
User31732 - Posts: 32
norvik, thank you. Now it almost like original OFA bars, but close of some bars shouldn't be at the high or at the low.
imageofa chart.jpg / V - Attached On 2014-01-25 08:10:59 UTC - Size: 193.76 KB - 2062 views
imageofa chart original.jpg / V - Attached On 2014-01-25 08:11:09 UTC - Size: 127.78 KB - 1865 views
Attachment Deleted.
[2014-01-27 15:27:52]
norvik - Posts: 22
Now it almost like original OFA bars, but close of some bars shouldn't be at the high or at the low.

I made one improvement, now "reversal" condition works only after the "exceeded" case occurred.
View is exactly like original bars..
imageofa.jpg / V - Attached On 2014-01-27 15:27:25 UTC - Size: 207.42 KB - 2135 views
attachmentOFARealChart.cpp - Attached On 2014-01-27 15:27:39 UTC - Size: 8.06 KB - 794 views
[2014-01-27 15:48:49]
User67150 - Posts: 3
norvik, could you post dll?
SC can not compile this cpp.
Date Time Of Last Edit: 2014-01-27 15:54:59
[2014-01-27 16:08:15]
norvik - Posts: 22
Sorry, I am using VS. Here is compiled dll.
attachmentOFARealChart.dll - Attached On 2014-01-27 16:08:06 UTC - Size: 89 KB - 793 views
[2014-01-27 16:29:55]
User67150 - Posts: 3
norvik, thanks, you are almost there, but still there are wrong bars in your version.
didn't want to discourage you, hope you'll make it right.

Date Time Of Last Edit: 2014-01-27 16:32:55
image2.png / V - Attached On 2014-01-27 16:28:47 UTC - Size: 74.34 KB - 1976 views
[2014-01-27 17:37:03]
User31732 - Posts: 32
User67150, try for 6/4 OFA 5/4 parameters. I'm sure it's exactly like OFA bars.
Norvik, many thanks!
[2014-01-27 20:46:31]
ejtrader - Posts: 688
Interesting bar type. Can anyone comment whether these bars have "true" Open/Close values - that are likely to be same during replay?

Thanks
[2014-01-28 05:43:04]
norvik - Posts: 22
but still there are wrong bars in your version.
I made this custom chart using the only public information from OFA webpage.
May be something is missed, Inglish is not my native language. Also I think that their description possible is not complete,
it is proprietary algo.
[2014-01-28 07:08:28]
User67150 - Posts: 3
User67150, try for 6/4 OFA 5/4 parameters. I'm sure it's exactly like OFA bars.

I tried various combinations, still not the same if compare with OFA.
If you have exactly the same - could you post the screen?

[2014-02-04 04:47:38]
Profile Trader - Posts: 168
OFA 6/4 Bars require that the price goes up 6 ticks consecutively and then pull back 4 ticks to start a new bar. So if it goes up 3 and then back one the count is started over for the 6 consecutive ticks. the 6 can be in either direction but has to uptick or downtick without reversing at all once the 6 ticks have been hit. After that happens a new bar is printed when 4 opposite directional ticks has happened. These would be done on reversal bars.
[2014-02-05 16:07:18]
Profile Trader - Posts: 168
Those that know how to program for SC is this something that SC is capable of doing with the Number Bar study?

I put together a excel spreadsheet each night that has levels like pivots, highs, lows, value areas etc. is there a way to import a excel spreadsheet into SC and have that place lines and label those lines what is in the spreadsheet?

Thanks for your insight.

Doug
[2014-08-03 21:44:35]
Moti - Posts: 63
Hello Norvik,

I will like to thank you for the code of OFA bar.

Profile trader describe the movement of bar:
" "OFA 6/4 Bars require that the price goes up 6 ticks consecutively and then pull back 4 ticks to start a new bar. So if it goes up 3 and then back one the count is started over for the 6 consecutive ticks. the 6 can be in either direction but has to uptick or downtick without reversing at all once the 6 ticks have been hit. After that happens a new bar is printed when 4 opposite directional ticks has happened. These would be done on reversal bars.""

Norvik, Please advice if your code work like the description ? If Not

would you like that I will translate the description above to Russian ?

Moti



[2015-08-22 00:00:25]
ejtrader - Posts: 688
Marcovith - For some reason the cpp file provided doesn't provide the same chart as the dll.

Would you please check and post the cpp file one more time?

Thanks
[2015-08-24 21:22:05]
norvik_ - Posts: 106
ejtrader, sorry, if you ask about the dll i formely posted here, i really can not exactly say on wich variant of code it was based. last version i have in attachment
attachmentOFARealChart.cpp - Attached On 2015-08-24 21:21:51 UTC - Size: 8.06 KB - 652 views
[2015-08-24 21:45:16]
ejtrader - Posts: 688
Thanks Norvik. Appreciate it.

Just that this doesn't match up the dll from post #10. Did you use the same cpp file for compiling that dll?

the cpp file doesn't compile by default ( there are few syntax errors ). After correcting them - the chart doesn't match up the dll.

I would try to see if there are any other missing portions for this.

thanks

as per the image - left side is based on the dll file
right side - based on the corrected cpp file.

screencast.com/t/a4Lw4EiIv9BT
[2015-08-25 20:43:04]
norvik_ - Posts: 106
Interesting. I will try to remember how I create it.
[2015-08-25 20:51:50]
ejtrader - Posts: 688
Thanks Norvik.

Attached is the cpp file to make it compilable( few syntax errors are addressed from the cpp file you have provided). Just that this doesn't provide the same output as the dll file you have uploaded.

Thanks
Date Time Of Last Edit: 2015-08-25 20:52:29
attachmentOFABars.cpp - Attached On 2015-08-25 20:51:09 UTC - Size: 9.08 KB - 713 views
[2015-08-25 22:59:43]
norvik_ - Posts: 106
Attached file is compiled without errors on VS 2010. Result is on a screenshort.
imageofa.jpg / V - Attached On 2015-08-25 22:58:54 UTC - Size: 146.44 KB - 2182 views
attachmentOFARealChart.cpp - Attached On 2015-08-25 22:59:10 UTC - Size: 7.94 KB - 690 views
[2015-08-26 01:03:24]
ejtrader - Posts: 688
Thanks Norvik. This cpp file works fine as expected :)

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

Login

Login Page - Create Account