Simple indicator missing the last bar

Questions about MultiCharts .NET and user contributed studies.
SSS
Posts: 14
Joined: 01 Apr 2013
Has thanked: 10 times
Been thanked: 2 times

Simple indicator missing the last bar

Postby SSS » 28 Aug 2013

Hello.

I have this simple indicator which exports OHLC data to a text file.

Code: Select all

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using System.IO;

namespace PowerLanguage.Indicator{
[UpdateOnEveryTickAttribute (false)]

public class ohlcExporter : IndicatorObject {
public ohlcExporter(object _ctx):base(_ctx){}
private IPlotObject plot1;
private StreamWriter outputStream;
private String outputTextFile;
string tickerName;

protected override void Create() {
plot1 = AddPlot(new PlotAttributes("", EPlotShapes.Line, Color.Red));
}

protected override void StartCalc() {
tickerName = Bars.Info.ASymbolInfo2.SymbolRoot;
outputTextFile = "c:\\" + tickerName + ".txt";
outputStream = new StreamWriter(outputTextFile, false);
outputStream.WriteLine("Instrument, Date, Open, High, Low, Close, Volume");
}
protected override void CalcBar(){
plot1.Set(Bars.Close[0]);
outputStream.Write(tickerName + ", ");
outputStream.Write(Bars.Time[0].Date.ToString("yyyyMMdd, "));
outputStream.Write(Bars.Open[0].ToString() + ", ");
outputStream.Write(Bars.High[0].ToString() + ", ");
outputStream.Write(Bars.Low[0].ToString() + ", ");
outputStream.Write(Bars.Close[0].ToString() + ", ");
outputStream.WriteLine(Bars.Volume[0].ToString());
if (Bars.LastBarOnChart) {
outputStream.Close();
}
}
}
}
My main problem with it is that it does not write the data for the very last bar on the chart. So if today is August 28th, the text file contains the data for all bars up to 27th, but not 28th.

I've tried changing the [UpdateOnEveryTickAttribute (false)] property to true. I've tried pasting all the .Write lines into the if (Bars.LastBarOnChart) condition. But no luck in either case.

Any guidance is appreciated.


(NOT SO IMPORTANT: The script seems to work fine (except for missing the last bar) on charts. But if I paste it into a market scanner, I sporadically get errors like cannot write to a closed stream, or file is being used by another process. This issue is not very pressing since I only have 2 tickers to look at for now, so I can manage with the indicator applied to a chart for the time being.)

User avatar
JoshM
Posts: 2195
Joined: 20 May 2011
Location: The Netherlands
Has thanked: 1544 times
Been thanked: 1565 times
Contact:

Re: Simple indicator missing the last bar

Postby JoshM » 28 Aug 2013

(NOT SO IMPORTANT: The script seems to work fine (except for missing the last bar) on charts. But if I paste it into a market scanner, I sporadically get errors like cannot write to a closed stream, or file is being used by another process. This issue is not very pressing since I only have 2 tickers to look at for now, so I can manage with the indicator applied to a chart for the time being.)
Perhaps closing the stream in the Destroy method prevents this error. See here (bottom of page).

SSS
Posts: 14
Joined: 01 Apr 2013
Has thanked: 10 times
Been thanked: 2 times

Re: Simple indicator missing the last bar

Postby SSS » 05 Sep 2013

(NOT SO IMPORTANT: The script seems to work fine (except for missing the last bar) on charts. But if I paste it into a market scanner, I sporadically get errors like cannot write to a closed stream, or file is being used by another process. This issue is not very pressing since I only have 2 tickers to look at for now, so I can manage with the indicator applied to a chart for the time being.)
Perhaps closing the stream in the Destroy method prevents this error. See here (bottom of page).
Thanks Josh.

I've been trying different ways of using this, but I get the error that I'm trying to write to an already closed stream.

I wonder if there's a way to make an indicator remove itself or turn itself off after reading the last bar. I've tried this in CalcBar:

Code: Select all

if (Bars.LastBarOnChart) {
outputStream.close();
base.DestroyImpl();
this.DestroyImpl();
}
and a whole bunch of .Destroy, .Dispose, etc attempts. Still no luck.

MidKnight
Posts: 343
Joined: 12 Aug 2012
Has thanked: 123 times
Been thanked: 56 times

Re: Simple indicator missing the last bar

Postby MidKnight » 06 Sep 2013

Hi there,

I would probably end up trying something like this. You need to remember some state of the very first time you get to the last bar on the chart

Code: Select all

.... private bool hasReachedLastBar = false;


protected override void CalcBar()
{
if (!hasReachedLastBar)
{
plot1.Set(Bars.Close[0]);
outputStream.Write(tickerName + ", ");
outputStream.Write(Bars.Time[0].Date.ToString("yyyyMMdd, "));
outputStream.Write(Bars.Open[0].ToString() + ", ");
outputStream.Write(Bars.High[0].ToString() + ", ");
outputStream.Write(Bars.Low[0].ToString() + ", ");
outputStream.Write(Bars.Close[0].ToString() + ", ");
outputStream.WriteLine(Bars.Volume[0].ToString());

if (Bars.LastBarOnChart)
{
hasReachedLastBar = true;
outputStream.Close();
}
}
}
I hope that helps somewhat. It's a bit tedious but this seems like what you need to do. OR you could just run what you had but outside of market hours - that way your closing of the stream will only fire once. But it looks like you just want to be able to export OHLC, date time stamp, and volume to a file? Why not just do this through the quotemanager symbol export feature? I must be missing something.....

With kind regards,
MK

SSS
Posts: 14
Joined: 01 Apr 2013
Has thanked: 10 times
Been thanked: 2 times

Re: Simple indicator missing the last bar

Postby SSS » 07 Sep 2013

Hi there,

I would probably end up trying something like this. You need to remember some state of the very first time you get to the last bar on the chart
Thanks for this MidKnight, on first look it seems to work, although now with the weekend on, I can't check how it works when "Update on Every Tick" is enabled and the market is live. I've tried using Data Playback. It doesn't generate an error like my code, but something is not quite right, which I'll check on Monday when the market goes live. Thanks again.
I hope that helps somewhat. It's a bit tedious but this seems like what you need to do. OR you could just run what you had but outside of market hours - that way your closing of the stream will only fire once. But it looks like you just want to be able to export OHLC, date time stamp, and volume to a file? Why not just do this through the quotemanager symbol export feature? I must be missing something.....

With kind regards,
MK
You're absolutely right, I want OHLC numbers and a date stamp. I have an old piece of software that requires the data in Metastock format.

The thing is, I actually need the data DURING market hours, especially when the day's High or Low changes. I never realized I could use the the Quote Manager for this, so thanks again for the pointer. I've checked it out, but unfortunately it doesn't quite work, as my old piece of software requires a header and a certain format. Programming the indicator allows me to format the data exactly the way my old software needs it.

Plus it's going to be tedious to open the Quote Manager, select tickers and do the export manually every time we get a new HOD or LOD. I've only got two symbols now in the Starter Edition of Multicharts, but I'm thinking ahead when I have a lot more instruments to look at.

Ideally, I'll have them listed in a Scanner window with the indicator applied to it. Or at least I'll create a workspace with a few charts that have the indicator applied to each. That way, every time I need an update I just open the workspace, let the indicators run and then close it.

SSS
Posts: 14
Joined: 01 Apr 2013
Has thanked: 10 times
Been thanked: 2 times

Re: Simple indicator missing the last bar

Postby SSS » 07 Sep 2013

You need more of the statements in this matter, so that we can understand. Thank you for sharing. I hope you happy
_________________
Dream to be A billionaire
I love to buy Diablo 3 Gold at http://www.vipdiablo3gold.com/
Hello zhulin.

The idea is to look at each bar of data, and write to a text file some information about that bar; then close the text file when we reach the last bar. To simplify the idea, let's assume I just want the number of that bar. Here's the code I started with:

Code: Select all

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using System.IO;

namespace PowerLanguage.Indicator{
[UpdateOnEveryTickAttribute (true)]

public class ExportBarNumber : IndicatorObject {
public ExportBarNumber(object _ctx):base(_ctx){}
private string myFilename;
private StreamWriter myStream;

protected override void Create() {
}

protected override void StartCalc() {
myFilename = "C:\\Testing.txt";
myStream = new StreamWriter(myFilename, false);
}

protected override void CalcBar(){
Output.WriteLine("Outputting Bar number: " + Bars.CurrentBar.ToString()); // to Output window
myStream.Write("Writing Bar number: " + Bars.CurrentBar.ToString()); //to text file

if (Bars.LastBarOnChart == true) {
myStream.Close();
}
}
}
}
When each bar is read, I'm (1) outputting the bar's number to the Output window, and (2) writing the bar number to the text file called "Testing.txt" via a StreamWriter object.

If you try running the above code (during market hours) on a simple chart with a few bars (try for example only 10 bars), you'll see the Output window has no issues, but writing to the text file hits an error because when a new tick arrives, it attempts to write to the text file that has already been closed.

Before MidKnight proposed his solution above, I'd gotten as far as this. In both StartCalc() and CalcBar(), I closed the StreamWriter after every write, then re-opened it (with append = true) whenever i needed to write to it again.

Code: Select all

protected override void StartCalc() {
myFilename = "C:\\Testing.txt";
myStream = new StreamWriter(myFilename, false);
myStream.Close();
}

protected override void CalcBar(){
Output.WriteLine("Outputting Bar number: " + Bars.CurrentBar.ToString());
if (myStream == null) {
myStream = new StreamWriter(myFilename, true);
myStream.Write("Writing Bar number: " + Bars.CurrentBar.ToString());
myStream.Close();
}

if (Bars.LastBarOnChart == true) {
myStream.Close();
}
}
}
While this seems to work, and I no longer get the error after every new tick, it involves an awful lot of writing to the hard disk, opening and closing text files every time, so I'm sure there must be a more efficient way. I'll try MidKnight's idea on Monday, and hopefully it should be fine.

User avatar
JoshM
Posts: 2195
Joined: 20 May 2011
Location: The Netherlands
Has thanked: 1544 times
Been thanked: 1565 times
Contact:

Re: Simple indicator missing the last bar

Postby JoshM » 07 Sep 2013

While this seems to work, and I no longer get the error after every new tick, it involves an awful lot of writing to the hard disk, opening and closing text files every time, so I'm sure there must be a more efficient way. I'll try MidKnight's idea on Monday, and hopefully it should be fine.
Hi SSS,

Since you also said:
The thing is, I actually need the data DURING market hours, especially when the day's High or Low changes.
Why not write once every x updates to the file, or immediately when a new High or Low is reached? That should give better performance since not every tick will need to be written immediately to a file.

In pseudo-code:

Code: Select all

int counter = 0;

static void WriteToFile(string textToWrite)
{
myWriter.WriteLine(textToWrite);

if (counter % 1000 == 0 || Close > DailyHigh || Close < DailyLow)
{
myWriter.Flush();
counter = 0;
}

counter++;
}
Edit: Forgot links. Here and here is more information about Flush. And on MSDN.

MidKnight
Posts: 343
Joined: 12 Aug 2012
Has thanked: 123 times
Been thanked: 56 times

Re: Simple indicator missing the last bar

Postby MidKnight » 07 Sep 2013

G'day tripple S,

So far you require:
- data export in a format you can control
- real-time exporting
- possible triggering of the export upon new hod/lod

Because you need the data done real-time, my code snippet won't work as the stream will be closed at last bar and then you are screwed :)

JoshM's solution sounds like it gets you closer to where you want to go. With my new understanding of your requirements it sounds like you don't really want to close the stream at all. I'm not proficient enough with C# or MC.net but maybe you only want to close the stream when the indicator is destroyed, just to be tidy. Also its probably tidy to add exception handling that will close the stream if there is any type of IO related exception and it notifies you in the MC.net popup.

I think you almost have what you need. I learned something in this thread, so thank you all posters.

With kind regards,
MK

User avatar
JoshM
Posts: 2195
Joined: 20 May 2011
Location: The Netherlands
Has thanked: 1544 times
Been thanked: 1565 times
Contact:

Re: Simple indicator missing the last bar

Postby JoshM » 08 Sep 2013

As I understand what you're trying to do SSS, I would do that as follows: (Which is surely not to say that this is the 'best' way)

Code: Select all

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using System.IO;

namespace PowerLanguage.Indicator
{
[UpdateOnEveryTick(true)]
[SkipIdenticalTicks(true)]
[SameAsSymbol(true)]
public class OHLC_Exporter : IndicatorObject
{
public OHLC_Exporter(object _ctx):base(_ctx){}

private StreamWriter myWriter;
private double dailyHigh = 0;
private double dailyLow = 99999999;
private int counter;
private string tickerName;

private string filename = @"C:\Temp\testoutput.txt";

protected override void Create()
{
myWriter = new StreamWriter(filename, true); // With FileAppend
myWriter.WriteLine("Instrument, Date, Open, High, Low, Close, Volume");
}

protected override void StartCalc()
{
tickerName = Bars.Info.ASymbolInfo2.SymbolRoot;
}

protected override void CalcBar()
{
// Reset daily high/low on new date
if (Bars.Time[0].Date != Bars.Time[1].Date)
{
dailyHigh = 0;
dailyLow = 9999999;
}

// Write to file on last bar on chart
if (Bars.LastBarOnChart == true && Environment.IsRealTimeCalc == true)
WriteToFile();

dailyHigh = Math.Max(Bars.Close[0], dailyHigh);
dailyLow = Math.Min(Bars.Close[0], dailyLow);
}

protected override void Destroy()
{
myWriter.Flush();
myWriter.Close();
}

private void WriteToFile()
{
myWriter.WriteLine(string.Format("{0};{1};{2};{3};{4};{5};{6}",
tickerName,
Bars.Time[0].ToString("yyyyMMdd HH:mm:ss"),
Bars.Open[0],
Bars.High[0],
Bars.Low[0],
Bars.Close[0],
Bars.Volume[0]));

if (counter % 100 == 0 || Bars.Close[0] > dailyHigh || Bars.Close[0] < dailyLow)
{
myWriter.Flush();
counter = 0;
}

counter++;
}
}
}
Which gives an output like:

Code: Select all

Instrument, Date, Open, High, Low, Close, Volume
XTI/USD;20130906 09:55:00;107,79;107,89;107,77;107,88;550
XTI/USD;20130906 09:55:00;107,79;107,9;107,77;107,9;600
XTI/USD;20130906 09:55:00;107,79;107,91;107,77;107,91;650
XTI/USD;20130906 09:55:00;107,79;107,91;107,77;107,9;650
XTI/USD;20130906 09:55:00;107,79;107,91;107,77;107,91;700
XTI/USD;20130906 10:00:00;107,92;107,92;107,92;107,92;50
XTI/USD;20130906 10:00:00;107,92;107,92;107,91;107,91;50
XTI/USD;20130906 10:00:00;107,92;107,92;107,91;107,92;100
XTI/USD;20130906 10:00:00;107,92;107,93;107,91;107,93;150
XTI/USD;20130906 10:00:00;107,92;107,94;107,91;107,94;200
XTI/USD;20130906 10:00:00;107,92;107,95;107,91;107,95;250
XTI/USD;20130906 10:00:00;107,92;107,96;107,91;107,96;300
XTI/USD;20130906 10:00:00;107,92;107,96;107,91;107,95;300
XTI/USD;20130906 10:00:00;107,92;107,96;107,91;107,96;350
XTI/USD;20130906 10:00:00;107,92;107,97;107,91;107,97;400
XTI/USD;20130906 10:00:00;107,92;107,98;107,91;107,98;450
XTI/USD;20130906 10:00:00;107,92;107,99;107,91;107,99;500
XTI/USD;20130906 10:00:00;107,92;108,01;107,91;108,01;550
XTI/USD;20130906 10:00:00;107,92;108,01;107,91;108;550
XTI/USD;20130906 10:00:00;107,92;108,01;107,91;108,01;600
XTI/USD;20130906 10:00:00;107,92;108,02;107,91;108,02;650
XTI/USD;20130906 10:00:00;107,92;108,03;107,91;108,03;700
XTI/USD;20130906 10:00:00;107,92;108,04;107,91;108,04;750
XTI/USD;20130906 10:00:00;107,92;108,05;107,91;108,05;800
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,07;825
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,06;825
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,07;875
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,06;875
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,05;875
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,06;925
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,05;925
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,04;925
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,03;925
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,04;975
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,03;975
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,04;1025
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,05;1075
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,04;1075
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,03;1075
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,04;1125
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,03;1125
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,04;1175
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,03;1175
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,02;1175
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,01;1175
XTI/USD;20130906 10:00:00;107,92;108,07;107,91;108,02;1225
PS:
1) This is just an example and not meant to be an copy-paste solution (for example, exception handling is missing).
2) I've tested it on Playback data since there's no real-time data now (weekend).

Tip: the free open source program SnakeTail is great for monitoring updating log files (I'm not affiliated, I just like it).

muee
Posts: 1
Joined: 16 Feb 2014

Re: Simple indicator missing the last bar

Postby muee » 16 Feb 2014

This was a spam message. It remains here while we are checking how exactly it has appeared.


Return to “MultiCharts .NET”