lazarus/components/tachart/demo/financial/main.pas

199 lines
6.1 KiB
ObjectPascal

unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, TAGraph, TAMultiSeries, TATools,
Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, ColorBox, types;
type
{ TMainForm }
TMainForm = class(TForm)
cbCandleStickSameColor: TCheckBox;
cbSeriesType: TComboBox;
ChartToolset1: TChartToolset;
cbUpColor: TColorBox;
cbDownColor: TColorBox;
DataPointHintTool_Details: TDataPointHintTool;
DataPointHintTool_All: TDataPointHintTool;
FinancialChart: TChart;
Label1: TLabel;
LblDown: TLabel;
LblUp: TLabel;
ohlcSeries: TOpenHighLowCloseSeries;
BottomPanel: TPanel;
TopPanel: TPanel;
procedure cbCandleStickSameColorChange(Sender: TObject);
procedure cbSeriesTypeChange(Sender: TObject);
procedure cbColorChange(Sender: TObject);
procedure DataPointHintTool_AllHint(ATool: TDataPointHintTool;
const {%H-}APoint: TPoint; var AHint: String);
procedure DataPointHintToolHintLocation(ATool: TDataPointHintTool;
AHintSize: TSize; var APoint: TPoint);
procedure DataPointHintTool_DetailsHint(ATool: TDataPointHintTool;
const {%H-}APoint: TPoint; var AHint: String);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.lfm}
uses
DateUtils;
const
DATA_FILE = 'data.txt';
{ TMainForm }
procedure TMainForm.FormCreate(Sender: TObject);
var
dataList: TStringList;
lines: TStringList;
fs: TFormatSettings;
i: Integer;
xDate: TDate;
yOpen, yClose, yHigh, yLow: Double;
begin
fs := DefaultFormatSettings;
fs.DateSeparator := '-';
fs.ShortDateFormat := 'd/mmm/yyyy';
fs.DecimalSeparator := '.';
dataList := TStringList.Create;
try
dataList.LoadFromFile(DATA_FILE);
lines := TStringList.Create;
try
for i:=1 to dataList.Count-1 do begin // skip header line
lines.CommaText := dataList[i];
xDate := ScanDateTime('yyyy-mm-dd', lines[0]);
yOpen := StrToFloat(lines[1], fs);
yHigh := StrToFloat(lines[2], fs);
yLow := StrToFloat(lines[3], fs);
yClose := StrToFloat(lines[4], fs);
// We don't use the date for x because we want to skip the weekends in the chart
// Therefore, we use the index and add the date as a label. Diplay of
// the data labels is activated by BottomAxis.Marks.Style = smsLabel.
ohlcSeries.AddXOHLC(i, yOpen, yHigh, yLow, yClose, DateToStr(xDate));
end;
finally
lines.Free;
end;
finally
dataList.Free;
end;
FinancialChart.BottomAxis.Marks.Source := ohlcSeries.ListSource;
end;
{ The combobox switches between OHLC and candle stick display modes. }
procedure TMainForm.cbSeriesTypeChange(Sender: TObject);
begin
ohlcSeries.Mode := TOHLCMode(CbSeriesType.ItemIndex);
cbCandleStickSameColor.Visible := cbSeriesType.ItemIndex = 1;
end;
procedure TMainForm.cbColorChange(Sender: TObject);
begin
ohlcSeries.LinePen.Color := cbUpColor.Selected;
ohlcSeries.DownLinePen.Color := cbDownColor.Selected;
ohlcSeries.CandlestickUpBrush.Color := cbUpColor.Selected;
ohlcSeries.CandleStickDownBrush.Color := cbDownColor.Selected;
end;
procedure TMainForm.cbCandleStickSameColorChange(Sender: TObject);
begin
if cbCandleStickSameColor.Checked then
ohlcSeries.CandlestickLinePen.Color := clDefault
else
ohlcSeries.CandleStickLinePen.Color := clBlack;
end;
{ This event handler returns the text to be displayed as a mouse-over hint.
We construct the text from the date, and the open, high, low, close values. }
procedure TMainForm.DataPointHintTool_AllHint(ATool: TDataPointHintTool;
const APoint: TPoint; var AHint: String);
var
ser: TOpenHighLowCloseSeries;
begin
ser := ATool.Series as TOpenHighLowCloseSeries;
AHint := AnsiToUTF8(Format('Date: %s'#13' Open: %.2m'#13' High: %.2m'#13' Low: %.2m'#13' Close: %.2m', [
FormatDateTime('dddddd', StrToDate(ser.ListSource[ATool.PointIndex]^.Text)),
ser.ListSource[ATool.PointIndex]^.GetY(ser.YIndexOpen),
ser.ListSource[ATool.PointIndex]^.GetY(ser.YIndexHigh),
ser.ListSource[ATool.PointIndex]^.GetY(ser.YIndexHigh),
ser.ListSource[ATool.PointIndex]^.GetY(ser.YIndexClose)
]));
end;
{ Similar to the method above. Displays only the date and the value clicked }
procedure TMainForm.DataPointHintTool_DetailsHint(ATool: TDataPointHintTool;
const APoint: TPoint; var AHint: String);
var
ser: TOpenHighLowCloseSeries;
idx: Integer;
yidx: Integer;
ohlcName: String;
begin
ser := ATool.Series as TOpenHighLowCloseSeries;
idx := ATool.PointIndex;
yidx := ATool.YIndex;
if yidx = ohlcSeries.YIndexClose then
ohlcName := 'Close'
else if yidx = ohlcSeries.YIndexHigh then
ohlcName := 'High'
else if yidx = ohlcSeries.YIndexLow then
ohlcName := 'Low'
else if yidx = ohlcSeries.YIndexOpen then
ohlcName := 'Open';
AHint := AnsiToUTF8(Format('Date: %s'#13' %s: %.2m', [
FormatDateTime('dddddd', StrToDate(ser.ListSource[idx]^.Text)),
ohlcName,
ser.ListSource[idx]^.GetY(yidx)
]));
end;
{ This event handler returns the location of the hint on the screen. To enhance
the assosciation with the data point and to avoid covering of the data point
we move center the hint window and move it up to the top of a OHLC/candle
data point.
Note:
The tool's UseApplicationHint must be set to FALSE for this even to fire. }
procedure TMainForm.DataPointHintToolHintLocation(ATool: TDataPointHintTool;
AHintSize: TSize; var APoint: TPoint);
var
ser: TOpenHighLowCloseSeries;
x, y: Integer;
begin
{ Calculate screen coordinates of the "high" point }
ser := ATool.Series as TOpenHighLowCloseSeries;
x := FinancialChart.XGraphToImage(ser.ListSource[ATool.PointIndex]^.X);
y := FinancialChart.YGraphToImage(ser.ListSource[ATool.PointIndex]^.YList[2]);
// "High" value, i.e. max of data point
// Center hint horizontally relative to data point
APoint.x := x - AHintSize.CX div 2;
// Move hint 4 pixels above the "High" data point
APoint.y := y - AHintSize.CY - 4;
// Hint coordinates are relative to screen
APoint := FinancialChart.ClientToScreen(APoint);
end;
end.