Page 1 of 2

Adding a marker on a Candle chart

Posted: Thu Mar 13, 2014 1:59 pm
by 16464098
I have a candle chart of a financial instrument over the past 10 years - what I want to do is indicate on the chart itself next to relevant candle a 'C' for a corporate action event and a 'N' for a name change event. Having read everything I can on this I cannot see how to do it. I thought perhaps adding something in the add chart part (where the '' is) would do it but it ignores anything there

Thanks

if (PlotArray.Open > PlotArray.High) OR
(PlotArray.Open < PlotArray.Low) OR
(PlotArray.Close > PlotArray.High) OR
(PlotArray.Close < PlotArray.Low) OR
(PlotArray.High < PlotArray.Low) then
Tmp := Series1.AddCandle(Series1.Count, PlotArray[i].Open,
PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '', clRED)
else
Tmp := Series1.AddCandle(Series1.Count, PlotArray[i].Open,
PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '', clNavy);
Series1.Labels[tmp] := DateToStr(EncodeDate (TheYear, TheMonth, TheDay));
Tmp1 := Series2.Add(PlotArray[i].Volume, '', ClNavy);
Series2.Labels[tmp1] := DateToStr(EncodeDate (TheYear, TheMonth, TheDay));

Re: Adding a marker on a Candle chart

Posted: Fri Mar 14, 2014 12:05 pm
by narcis
Hi Barry,
Barry wrote:I thought perhaps adding something in the add chart part (where the '' is) would do it but it ignores anything there
By default, Candle series don't display series marks, you should make them visible with Series1.Marks.Visible:=True;, which works fine here:

Code: Select all

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
    temp: TDateTime;
begin
  Chart1.View3D:=False;

  Series1.Marks.Visible:=True;

  for i:=0 to 10 do
  begin
    temp:= Now + i;

    if (i mod 3 = 0) then
      Series1.AddOHLC(temp, random, random, random, random, 'multiple of 3', clTeeColor)
    else
      if (i mod 2 = 0) then
        Series1.AddOHLC(temp, random, random, random, random, 'multiple of 2', clTeeColor)
      else
        Series1.AddOHLC(temp, random, random, random, random, 'none', clTeeColor)
  end;
end;

Re: Adding a marker on a Candle chart

Posted: Fri Mar 14, 2014 2:35 pm
by 16464098
Thanks for this, its better but not right

No matter what I put in the marks part I always get a date.

so

Tmp := Series1.AddCandle(Series1.Count, PlotArray.Open,
PlotArray.High, PlotArray.Low, PlotArray.Close, 'E', clRED)

Always displays a Date not 'E'

Thanks for your help

Re: Adding a marker on a Candle chart

Posted: Fri Mar 14, 2014 2:43 pm
by narcis
Hi Barry,

Try forcing marks to display text labels with Marks.Style property

Code: Select all

  Series1.Marks.Style:=smsLabel;
If this doesn't help please attach a simple example project we can run "as-is" to reproduce the problem here.

Thanks in advance.

Re: Adding a marker on a Candle chart

Posted: Fri Mar 14, 2014 3:00 pm
by 16464098
Sorry but that didn't work, it still displays a date, I will get you a simple project over the weekend as its right in the middle of a huge piece of code so I will need to work on that.

Barry

Re: Adding a marker on a Candle chart

Posted: Fri Mar 14, 2014 3:03 pm
by 16464098
Please can you also give me the options for marks.style as smsvalue works and displays a value

Thanks

Barry

Re: Adding a marker on a Candle chart

Posted: Fri Mar 14, 2014 3:06 pm
by narcis
Hi Barry,

Those are all options available:

Code: Select all

  TSeriesMarksStyle=( smsValue,             { 1234 }
                      smsPercent,           { 12 % }
                      smsLabel,             { Cars }
                      smsLabelPercent,      { Cars 12 % }
                      smsLabelValue,        { Cars 1234 }
                      smsLegend,            { (Legend.Style) }
                      smsPercentTotal,      { 12 % of 1234 }
                      smsLabelPercentTotal, { Cars 12 % of 1234 }
                      smsXValue,            { 1..2..3.. or 21/6/2014 }
                      smsXY,                { 123 456 }
                      smsSeriesTitle,       { Series1 }
                      smsPointIndex,        { 1..2..3... }
                      smsPercentRelative,   { 100%..90%..120%... }
                      smsLabelPercentValue  { Cars 12 % 1234 }
                      );
smsLabel is the default value.

Re: Adding a marker on a Candle chart

Posted: Fri Mar 14, 2014 3:47 pm
by 16464098
Here is a sample small bit of code that shows the problem.

There are 2 isuses

1. It shows a mark on every line, I assumed it would only show one when i=3
2. Each mark is a date

I'm expecting '3' when i=3 else nothing

Code: Select all


unit Chartmain;

interface

uses
  SysUtils, Windows, Messages, Classes, Graphics, Controls, StrUtils,
  Forms, Dialogs, StdCtrls, ipwCore,  ipwIPPort,  ipwHTTP,
  ExtCtrls, ipscore, ipshttps, DateUtils, TeEngine, TeeProcs, Chart, Series,
  OHLChart, CandleCh, TeeTools, ComCtrls, Grids, VclTee.TeeGDIPlus;

type
  TForm1 = class(TForm)
    Chart1: TChart;
    ChartTool1: TCursorTool;
    Series1: TCandleSeries;
    procedure FormCreate(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

type
  PriceRec = Record
    Date  : String;
    Open  : Double;
    High  : Double;
    Low   : Double;
    Close : Double;
  End;


implementation


{$R *.DFM}


procedure TForm1.FormCreate (Sender: TObject);

Var
  i                 : Integer;
  Tmp               : Integer;
  PlotArray         : Array[0..10] of PriceRec;

begin

  // Seed the array

  for i := 0 to 10 do
    Begin
      PlotArray[i].Open := 2;
      PlotArray[i].High := 4;
      PlotArray[i].Low := 2;
      PlotArray[i].Close := 3;
    End;

  Series1.Clear;
  Series1.Active := True;
  Series1.Visible := True;
  Chart1.Title.Caption := 'Steema Marks Demo';
  Series1.Marks.Visible := True;
  Series1.Marks.Style := smslabel;
  for I := 0 to 10 Do
    Begin
      if i = 3 then
        Tmp := Series1.AddCandle(Series1.Count, PlotArray[i].Open,
                        PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '3', clNavy)
      else
        Tmp := Series1.AddCandle(Series1.Count, PlotArray[i].Open,
                        PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '', clNavy);
      Series1.Labels[tmp] := DateToStr(EncodeDate (2014, 1, i+1));
    End;
end;


// -----------------------------------------------------------------------------



end.


I have attached the entire sample project

Re: Adding a marker on a Candle chart

Posted: Fri Mar 14, 2014 4:19 pm
by narcis
Hi Barry,
1. It shows a mark on every line, I assumed it would only show one when i=3
This looks like a bug to me. When there's an empty string mark nothing should be displayed instead of copying the same mark text for all points. I have added the defect to the bug list (ID639). If you sign up to bugzilla you'll be able to receive automatic status updates. Also, a workaround is adding OnGetMarkText event like this:

Code: Select all

procedure TForm1.Series1GetMarkText(Sender: TChartSeries;
  ValueIndex: Integer; var MarkText: String);
begin
  if Series1.Labels[ValueIndex]='' then
    MarkText:='';
end;
2. Each mark is a date
That's because of you are setting them with this line:

Code: Select all

      Series1.Labels[tmp] := DateToStr(EncodeDate (2014, 1, i+1));
Commenting it out solves the problem. So that your complete code would look like this:

Code: Select all

procedure TForm1.FormCreate (Sender: TObject);

Var
  i                 : Integer;
  PlotArray         : Array[0..10] of PriceRec;

begin

  // Seed the array

  for i := 0 to 10 do
    Begin
      PlotArray[i].Open := 2;
      PlotArray[i].High := 4;
      PlotArray[i].Low := 2;
      PlotArray[i].Close := 3;
    End;

  Series1.Clear;
  Series1.Active := True;
  Series1.Visible := True;
  Chart1.Title.Caption := 'Steema Marks Demo';
  Series1.Marks.Visible := True;
  //Series1.Marks.Style := smslabel;
  for I := 0 to 10 Do
    Begin
      if i = 3 then
        Series1.AddCandle(Series1.Count, PlotArray[i].Open,
                        PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '3', clNavy)
      else
        Series1.AddCandle(Series1.Count, PlotArray[i].Open,
                        PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '', clNavy);
    End;
end;


// -----------------------------------------------------------------------------



procedure TForm1.Series1GetMarkText(Sender: TChartSeries;
  ValueIndex: Integer; var MarkText: String);
begin
  if Series1.Labels[ValueIndex]='' then
    MarkText:='';
end;

Re: Adding a marker on a Candle chart

Posted: Fri Mar 14, 2014 4:35 pm
by 16464098
Re the 1st point, thanks, I will track the bug,

Re the 2nd point - sorry that's not correct, If I comment that line out the dates are not displayed along the x-axis although interestingly if I do comment it out then '3' appears on the X-axis under the relevant candle.

Just to be clear on what I want

1. I want dates along the X-axis
2. I want to be able to display a Mark against the actual candle where i=3

I think perhaps from your response this was not clear

Thanks

Barry

Re: Adding a marker on a Candle chart

Posted: Fri Mar 14, 2014 4:42 pm
by narcis
Hi Barry,

Ok, in that case I'd recommend adding X axis dates when populating series and forcing them to be displayed at the bottom axis using LabelStyle property, for example:

Code: Select all

  Chart1.Axes.Bottom.LabelStyle:=talValue;

  for I := 0 to 10 Do
    Begin
      if i = 3 then
        Series1.AddCandle(EncodeDate (2014, 1, i+1), PlotArray[i].Open,
                        PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '3', clNavy)
      else
        Series1.AddCandle(EncodeDate (2014, 1, i+1), PlotArray[i].Open,
                        PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '', clNavy);
    End;

Re: Adding a marker on a Candle chart

Posted: Fri Mar 14, 2014 4:58 pm
by 16464098
Sorry - my understanding is that does not skip weekends properly then, am I incorrect ? That is why I have been using the tmp= method as suggested in your doc

Also I tried this (below) and there is still a mark on every bar - have I missed something ?

Code: Select all


unit Chartmain;

interface

uses
  SysUtils, Windows, Messages, Classes, Graphics, Controls, StrUtils,
  Forms, Dialogs, StdCtrls, ipwCore,  ipwIPPort,  ipwHTTP,
  ExtCtrls, ipscore, ipshttps, DateUtils, TeEngine, TeeProcs, Chart, Series,
  OHLChart, CandleCh, TeeTools, ComCtrls, Grids, VclTee.TeeGDIPlus;

type
  TForm1 = class(TForm)
    Chart1: TChart;
    ChartTool1: TCursorTool;
    Series1: TCandleSeries;
    procedure FormCreate(Sender: TObject);
    procedure SeriesGetMarkText (Sender: TChartSeries;
                  valueindex: Integer; Var MarkText: String);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

type
  PriceRec = Record
    Date  : String;
    Open  : Double;
    High  : Double;
    Low   : Double;
    Close : Double;
  End;


implementation


{$R *.DFM}

procedure TForm1.SeriesGetMarkText (Sender: TChartSeries;
                  valueindex: Integer; Var MarkText: String);

Begin
  if Series1.Labels[ValueIndex] = '' then
    MarkText := '';

End;


procedure TForm1.FormCreate (Sender: TObject);

Var
  i                 : Integer;
//   Tmp               : Integer;
  PlotArray         : Array[0..10] of PriceRec;

begin

  // Seed the array

  for i := 0 to 10 do
    Begin
      PlotArray[i].Open := 2;
      PlotArray[i].High := 4;
      PlotArray[i].Low := 2;
      PlotArray[i].Close := 3;
    End;

  Series1.Clear;
  Series1.Active := True;
  Series1.Visible := True;
  Chart1.Title.Caption := 'Steema Marks Demo';
  Series1.Marks.Visible := True;
  Series1.Marks.Style := smslabel;
  Chart1.Axes.Bottom.LabelStyle := talValue;
  for I := 0 to 10 Do
    Begin
      if i = 3 then
        Series1.AddCandle(EncodeDate (2014, 1, i+1), PlotArray[i].Open,
                        PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '3', clNavy)
      else
        Series1.AddCandle(EncodeDate (2014, 1, i+1), PlotArray[i].Open,
                        PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '', clNavy);

    End;
end;


// -----------------------------------------------------------------------------



end.


Re: Adding a marker on a Candle chart

Posted: Mon Mar 17, 2014 9:48 am
by narcis
Hi Barry,

Sorry, I didn't understand you wanted to skip weekends. In that case my recommendation would be inverting the functionality, using labels as you originally did and customizing them in the OnGetMarkText event, for example:

Code: Select all

unit Chartmain;

interface

uses
  SysUtils, Windows, Messages, Classes, Graphics, Controls, StrUtils,
  Forms, Dialogs, StdCtrls, ExtCtrls, DateUtils, TeEngine, TeeProcs, Chart,
  Series, OHLChart, CandleCh, TeeTools, ComCtrls, Grids, TeeGDIPlus;

type
  TForm1 = class(TForm)
    Chart1: TChart;
    ChartTool1: TCursorTool;
    Series1: TCandleSeries;
    procedure FormCreate(Sender: TObject);
    procedure Series1GetMarkText(Sender: TChartSeries; ValueIndex: Integer;
      var MarkText: String);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

type
  PriceRec = Record
    Date  : String;
    Open  : Double;
    High  : Double;
    Low   : Double;
    Close : Double;
  End;


implementation


{$R *.DFM}


procedure TForm1.FormCreate (Sender: TObject);

Var
  i                 : Integer;
  Tmp               : Integer;
  PlotArray         : Array[0..10] of PriceRec;

begin

  // Seed the array

  for i := 0 to 10 do
    Begin
      PlotArray[i].Open := 2;
      PlotArray[i].High := 4;
      PlotArray[i].Low := 2;
      PlotArray[i].Close := 3;
    End;

  Series1.Clear;
  Series1.Active := True;
  Series1.Visible := True;
  Chart1.Title.Caption := 'Steema Marks Demo';
  Series1.Marks.Visible := True;
  //Series1.Marks.Style := smslabel;
  //Chart1.Axes.Bottom.LabelStyle:=talValue;

  for I := 0 to 10 Do
    Begin
      if i = 3 then
        Tmp := Series1.AddCandle(Series1.Count, PlotArray[i].Open,
                        PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '3', clNavy)
      else
        Tmp := Series1.AddCandle(Series1.Count, PlotArray[i].Open,
                        PlotArray[i].High, PlotArray[i].Low, PlotArray[i].Close, '', clNavy);

      Series1.Labels[tmp] := DateToStr(EncodeDate (2014, 1, i+1));
    End;
end;


// -----------------------------------------------------------------------------



procedure TForm1.Series1GetMarkText(Sender: TChartSeries;
  ValueIndex: Integer; var MarkText: String);
begin
  if (ValueIndex=3) then
    MarkText:='3'
  else
    MarkText:='';
end;

end.

Re: Adding a marker on a Candle chart

Posted: Mon Mar 17, 2014 10:28 am
by 16464098
Sorry but this is now back where I started, just to make sure I cut and pasted your code and this is the result.

Pls see attached jpg

Barry

Re: Adding a marker on a Candle chart

Posted: Mon Mar 17, 2014 10:32 am
by narcis
Hi Barry,

Besides copying the code you need to subscribe the OnGetMarkText event in the series at design-time or at run-time like this:

Code: Select all

  Series1.OnGetMarkText:=Series1GetMarkText;