SmartQuant Discussion
http://www.smartquant.com/forums/

Custom Build Bars From Trades
http://www.smartquant.com/forums/viewtopic.php?f=46&t=5882
Page 1 of 1

Author:  jherr [ Thu Sep 06, 2007 8:19 am ]
Post subject:  Custom Build Bars From Trades

I wanted more control over how my charts were being drawn, so I wrote some custom BuildBarsFromTrades functions.

Let me know if you see any bugs. Thanks!

-Jeremy

Code:
//This set of BuildBarsFromTrades functions is an alternative to
//the built-in Build Bars From Trades feature.

//It does not overwrite trade data like the built-in feature does when there are multiple trades
//with the same timestamp.  Instead, it merges the new trade into the previous bar by adding to volume
//and adjusting the high, low, close etc.

//Building your own bars gives you the opportunity to apply custom filtering

//Remember to uncheck "Build Bars From Trades" for all market data

using System;
using System.Drawing;
using OpenQuant.API;
using OpenQuant.API.Indicators;

public class MyStrategy : Strategy
{
   public override void OnTrade(Trade trade)
   {
      if(trade.Price > 0 && trade.Size > 0) {
         BuildBarsFromTrades(BarType.Time,60,Trades,Bars);
         //BuildBarsFromTrades(BarType.Tick,100,Trades,Bars);
         //BuildBarsFromTrades(BarType.Volume,100,Trades,Bars);
      }
   }

   public void BuildBarsFromTrades(BarType barType, long barSize, TradeSeries trades, BarSeries bars)
   {
      switch(barType)
      {
         case BarType.Time:
            BuildTimeBarsFromTrades(barSize,trades.Last,bars);
            break;
         case BarType.Tick:
            BuildTickBarsFromTrades(barSize,trades,bars);
            break;
         case BarType.Volume:      
            BuildVolumeBarsFromTrades(barSize,trades.Last,bars);
            break;
      }
   
   }            
         
   public void BuildTimeBarsFromTrades(long barSize, Trade trade, BarSeries bars)
   {
      if(barSize < 1){
         throw(new Exception("barSize must be > 0"));
      }

      DateTime nextBarEndTime = new DateTime();
      if(bars.Count > 0){   //calculate the end time of the last bar
         long lastBarEndInSeconds = bars.Last.EndTime.Ticks / 10000000;
         long nextBarEndInSeconds = ((lastBarEndInSeconds + barSize)/barSize)*barSize;
         nextBarEndTime = nextBarEndTime.AddSeconds(nextBarEndInSeconds);
      }
      if(trade.DateTime < nextBarEndTime)
      {    //merge bar into previous bar
         bars.Add(BarType.Time,barSize,bars.Last.BeginTime, trade.DateTime,
            bars.Last.Open,
            Math.Max(bars.Last.High,trade.Price),
            Math.Min(bars.Last.Low,trade.Price),
            Trade.Price,
            bars.Last.Volume + trade.Size,
            0);  //Replaces the last bar
      }else{
         //Add new bar   
         bars.Add(BarType.Time,barSize,
            trade.DateTime,trade.DateTime,
            trade.Price,trade.Price,trade.Price,trade.Price,
            trade.Size,0);
      }
   }
   
   public void BuildTickBarsFromTrades(long barSize, TradeSeries trades, BarSeries bars)
   {
      Trade trade = trades.Last;
      if(barSize < 1){
         throw(new Exception("barSize must be > 0"));
      }
      //check if the last bar is full

      if(bars.Count > 0 && (((trades.Count / barSize)*barSize)< trades.Count))
      {    //merge bar into previous bar
         bars.Add(BarType.Tick,barSize,bars.Last.BeginTime, trade.DateTime,
            bars.Last.Open,
            Math.Max(bars.Last.High,trade.Price),
            Math.Min(bars.Last.Low,trade.Price),
            trade.Price,
            bars.Last.Volume + trade.Size,
            0);  //Replaces the last bar
      }else{
         //Add a small amount of time to the new bar
         //new bar must be later than last bar or it will replace the last bar.
         DateTime newTradeTime = trade.DateTime;
         if(bars.Count > 0 && bars.Last.BeginTime >= trade.DateTime){
            newTradeTime = bars.Last.BeginTime.AddTicks(1);   
         }else{
            newTradeTime = trade.DateTime;
         }         
         //Add new bar   
         bars.Add(BarType.Tick,barSize,
            newTradeTime,newTradeTime,
            trade.Price,trade.Price,trade.Price,trade.Price,
            trade.Size,0);
      }            
   }

   public void BuildVolumeBarsFromTrades(long barSize, Trade trade, BarSeries bars)
   {
      if(barSize < 1){
         throw(new Exception("barSize must be > 0"));
      }

      //make sure not to access bars.Last if there are no bars
      //volumeRemaining is the unfilled portion of the last bar
      DateTime newTradeTime = trade.DateTime;
      long volumeRemaining = 0;
      if(bars.Count > 0) {
         //new trade must be later than previous bar or it won't add.
         if(bars.Last.BeginTime >= trade.DateTime){
            newTradeTime = bars.Last.BeginTime.AddTicks(1);   
         }         
         volumeRemaining =  barSize - bars.Last.Volume;
      }   
      //merge with last volume bar
      long volumeAdd = 0;
      if(volumeRemaining > 0){
         volumeAdd = Math.Min(volumeRemaining,trade.Size);
         bars.Add(BarType.Volume,barSize,bars.Last.BeginTime, trade.DateTime,
            bars.Last.Open,
            Math.Max(bars.Last.High,trade.Price),
            Math.Min(bars.Last.Low,trade.Price),
            trade.Price,
            bars.Last.Volume + volumeAdd,
            0);  //Replaces the last bar
      }
      //deduct the volume that was just added from volumeRemaining
      volumeRemaining = trade.Size - volumeAdd;
      //add new volume bars until there is no more volumeRemaining
      while(volumeRemaining > 0){
         volumeAdd = Math.Min(volumeRemaining,barSize);
         bars.Add(BarType.Volume,barSize,
            newTradeTime,newTradeTime,
            trade.Price,trade.Price,trade.Price,trade.Price,
            volumeAdd,0);
         volumeRemaining = volumeRemaining - volumeAdd;
         //new trade must be later than previous bar or it won't add.
         newTradeTime = bars.Last.BeginTime.AddTicks(1);   
      }                  
   }
} //MyStrategy()







Author:  Dr. Anton Fokin [ Thu Sep 06, 2007 8:51 am ]
Post subject: 

Hi,

thanks for sharing this code.

I think this

Quote:
It does not overwrite trade data like the built-in feature does when there are multiple trades with the same timestamp


is not really true or you wanted to say something different. OpenQuant never overrides trades with the same timestamp. It does override bars with the same timestamp when you add bars to the database or BarSeries. All bars should have unique beginning date time.

Regards,
Anton

Author:  jherr [ Thu Sep 06, 2007 9:06 am ]
Post subject: 

Dr. Anton Fokin wrote:
Hi,

thanks for sharing this code.

I think this

Quote:
It does not overwrite trade data like the built-in feature does when there are multiple trades with the same timestamp


is not really true or you wanted to say something different. OpenQuant never overrides trades with the same timestamp. It does override bars with the same timestamp when you add bars to the database or BarSeries. All bars should have unique beginning date time.

Regards,
Anton


I wrote this because I was not seeing all the trades on tick bar charts. So my comments are in reference to bars and bar charts. Sorry for not being more specific.

Page 1 of 1 All times are UTC + 3 hours
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/