747 lines
23 KiB
ObjectPascal
747 lines
23 KiB
ObjectPascal
unit MainForm;
|
|
|
|
interface
|
|
|
|
{.$define TICKDATA}
|
|
|
|
uses
|
|
System.SysUtils,
|
|
System.Types,
|
|
System.UITypes,
|
|
System.Classes,
|
|
System.Variants,
|
|
System.DateUtils,
|
|
System.Generics.Collections,
|
|
System.Rtti,
|
|
System.Math,
|
|
FMX.Types,
|
|
FMX.Controls,
|
|
FMX.Forms,
|
|
FMX.Graphics,
|
|
FMX.Dialogs,
|
|
FMX.Controls.Presentation,
|
|
FMX.StdCtrls,
|
|
FMX.ListView.Types,
|
|
FMX.ListView.Appearances,
|
|
FMX.ListView.Adapters.Base,
|
|
FMX.ListView,
|
|
FMX.Memo.Types,
|
|
FMX.ScrollBox,
|
|
FMX.Memo,
|
|
FMX.Objects,
|
|
Myc.Futures,
|
|
Myc.Trade.Types,
|
|
Myc.Trade.DataStream,
|
|
Myc.Trade.Pipeline,
|
|
Myc.Data.Series,
|
|
Myc.Data.Pipeline,
|
|
Myc.Signals,
|
|
Myc.Mutable,
|
|
Myc.Signals.FMX,
|
|
Myc.TaskManager,
|
|
Myc.Aura.Module,
|
|
Myc.Data.Scalar,
|
|
Myc.Data.Keyword,
|
|
FMX.ListBox,
|
|
FMX.Layouts,
|
|
FMX.TreeView,
|
|
FMX.TabControl,
|
|
FMX.Menus,
|
|
System.ImageList,
|
|
FMX.ImgList,
|
|
System.Actions,
|
|
FMX.ActnList,
|
|
DynamicFMXControl,
|
|
Myc.FMX.Chart,
|
|
Myc.Trade.Indicators,
|
|
Myc.Trade.Indicators.Common,
|
|
Myc.Core.FileCache,
|
|
StrategyTest,
|
|
TestMethodCallFromRecordParams;
|
|
|
|
type
|
|
TForm1 = class(TForm)
|
|
LogMemo: TMemo;
|
|
MainPanel: TPanel;
|
|
SymbolsComboBox: TComboBox;
|
|
RandomBox: TCheckBox;
|
|
LoadButton: TButton;
|
|
RandomButton: TButton;
|
|
ChartButton: TButton;
|
|
StopButton: TButton;
|
|
Splitter1: TSplitter;
|
|
ActionList: TActionList;
|
|
AddWorkspaceAction: TAction;
|
|
WorkspacePanel: TPanel;
|
|
TabControl: TTabControl;
|
|
ToolBar: TToolBar;
|
|
AddWorkspaceButton: TSpeedButton;
|
|
ObjectsPanel: TPanel;
|
|
ObjectsTabControl: TTabControl;
|
|
ModulesTabItem: TTabItem;
|
|
TreeView: TTreeView;
|
|
TestButton: TSpeedButton;
|
|
TestAction: TAction;
|
|
TestPopup: TPopup;
|
|
FlowLayout: TFlowLayout;
|
|
StrategyButton: TSpeedButton;
|
|
Strat2Button: TSpeedButton;
|
|
Button1: TButton;
|
|
Button2: TButton;
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure StopButtonClick(Sender: TObject);
|
|
procedure TreeViewDblClick(Sender: TObject);
|
|
procedure AddWorkspaceActionExecute(Sender: TObject);
|
|
procedure Button1Click(Sender: TObject);
|
|
procedure Button2Click(Sender: TObject);
|
|
procedure LogMemoChange(Sender: TObject);
|
|
procedure Strat2ButtonClick(Sender: TObject);
|
|
procedure TestActionExecute(Sender: TObject);
|
|
procedure StrategyButtonClick(Sender: TObject);
|
|
private
|
|
FOnEvent: TNotifyEvent;
|
|
{ Private declarations }
|
|
FFileCache: IDataFileCache<TArray<TBytes>>;
|
|
FServer: IDataServer;
|
|
FSymbols: TFuture<TArray<String>>;
|
|
FTerminate: TEvent;
|
|
FProcessDone: TState;
|
|
FApplication: IAuraApplication;
|
|
FModulesItem: TTreeViewItem;
|
|
function SelectedSymbol: String;
|
|
procedure ExecuteStrategy(const Symbol: String; Timeframe: TTimeframe; const Consumer: IConsumer<TDataPoint<TOhlcItem>>);
|
|
|
|
public
|
|
procedure NewWorkspace;
|
|
function CurrLayout<T: TControl>: T;
|
|
procedure AlignControl(Control: TControl);
|
|
function CreateStrategy2(Timeframe: TTimeframe): IConsumer<TDataPoint<TOhlcItem>>;
|
|
|
|
published
|
|
property OnEvent: TNotifyEvent read FOnEvent write FOnEvent;
|
|
end;
|
|
|
|
var
|
|
Form1: TForm1;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Myc.Data.Records,
|
|
TestModule,
|
|
Strategy2;
|
|
|
|
{$R *.fmx}
|
|
|
|
procedure TForm1.NewWorkspace;
|
|
var
|
|
tab: TTabItem;
|
|
begin
|
|
var ws: IAuraWorkspace := TMycAuraWorkspace.Create('New workspace', tmTesting);
|
|
FApplication.Workspaces.Insert(-1, ws);
|
|
|
|
tab := TabControl.Add;
|
|
tab.Text := ws.Caption;
|
|
tab.Tag := NativeInt(ws);
|
|
|
|
var scrollbox := TVertScrollBox.Create(Self);
|
|
scrollbox.Parent := tab;
|
|
scrollbox.Align := TAlignLayout.Client;
|
|
|
|
tab.ProcessSignal(ws.Name.Changed, procedure begin tab.Text := ws.Caption; end);
|
|
end;
|
|
|
|
procedure TForm1.StopButtonClick(Sender: TObject);
|
|
begin
|
|
FTerminate.Notify;
|
|
TaskManager.WaitFor(FProcessDone);
|
|
|
|
var Layout := CurrLayout<TVertScrollBox>;
|
|
if Layout <> nil then
|
|
begin
|
|
Layout.Content.DeleteChildren;
|
|
Layout.Repaint;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.TreeViewDblClick(Sender: TObject);
|
|
begin
|
|
var sel := TreeView.Selected as TTreeViewItem;
|
|
|
|
var parent := sel.ParentItem;
|
|
if parent = nil then
|
|
exit;
|
|
|
|
if parent = FModulesItem then
|
|
begin
|
|
if (TabControl.ActiveTab <> nil) and (TabControl.ActiveTab.Tag <> 0) then
|
|
begin
|
|
var ws := IAuraWorkspace(TabControl.ActiveTab.Tag);
|
|
var module := FApplication.Modules[sel.TagString];
|
|
if (ws <> nil) and (module <> nil) then
|
|
module.SetupWorkspace(ws);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.FormCreate(Sender: TObject);
|
|
begin
|
|
FApplication := TMycAuraApplication.Create;
|
|
|
|
FModulesItem := TTreeViewItem.Create(Self);
|
|
FModulesItem.Text := 'Modules';
|
|
|
|
const modName = 'Test_Module';
|
|
|
|
FApplication.RegisterModule(modName, TTestModule.Create('Test-Module', 1));
|
|
|
|
TreeView.AddObject(FModulesItem);
|
|
FModulesItem.ProcessSignal(
|
|
FApplication.ModuleNames.Changed,
|
|
procedure
|
|
begin
|
|
FModulesItem.BeginUpdate;
|
|
try
|
|
while FModulesItem.Count > 0 do
|
|
FModulesItem[0].Free;
|
|
var mods := FApplication.ModuleNames.Value;
|
|
for var i := 0 to High(mods) do
|
|
begin
|
|
var ModItem := TTreeViewItem.Create(Self);
|
|
ModItem.Text := mods[i];
|
|
ModItem.DragMode := TDragMode.dmAutomatic;
|
|
ModItem.Text := 'Module-' + mods[i];
|
|
ModItem.TagString := mods[i];
|
|
FModulesItem.AddObject(ModItem);
|
|
end;
|
|
FModulesItem.ExpandAll;
|
|
finally
|
|
FModulesItem.EndUpdate;
|
|
end;
|
|
end
|
|
);
|
|
|
|
FTerminate := TEvent.CreateEvent;
|
|
|
|
// Create an instance of the TAuraTABFileServer. The server can be reused for multiple stream creations. [364]
|
|
FFileCache := TDataFileCache<TArray<TBytes>>.Create;
|
|
{$ifdef TICKDATA}
|
|
FServer := TTickFileServer.Create(FFileCache, '\\COFFEE\TickData\Pepperstone');
|
|
{$else}
|
|
FServer := TM1FileServer.Create(FFileCache, '\\COFFEE\TickData\Pepperstone');
|
|
{$endif}
|
|
|
|
SymbolsComboBox.Enabled := false;
|
|
ChartButton.Enabled := false;
|
|
LoadButton.Enabled := false;
|
|
|
|
FSymbols := FServer.EnumerateSymbols;
|
|
|
|
SymbolsComboBox.ProcessSignal(
|
|
FSymbols.Done.Signal,
|
|
procedure
|
|
begin
|
|
SymbolsComboBox.BeginUpdate;
|
|
try
|
|
SymbolsComboBox.Items.Clear;
|
|
SymbolsComboBox.Items.AddStrings(FSymbols.WaitFor);
|
|
if SymbolsComboBox.Items.Count > 0 then
|
|
begin
|
|
if SymbolsComboBox.ItemIndex < 0 then
|
|
SymbolsComboBox.ItemIndex := SymbolsComboBox.Items.IndexOf('GER40');
|
|
SymbolsComboBox.Enabled := true;
|
|
ChartButton.Enabled := true;
|
|
LoadButton.Enabled := true;
|
|
end;
|
|
finally
|
|
SymbolsComboBox.EndUpdate;
|
|
end;
|
|
end
|
|
);
|
|
|
|
NewWorkspace;
|
|
|
|
IndicatorRegistry.LogRegistry(LogMemo.Lines);
|
|
end;
|
|
|
|
procedure TForm1.FormDestroy(Sender: TObject);
|
|
begin
|
|
FSymbols.WaitFor;
|
|
FTerminate.Notify;
|
|
TaskManager.WaitFor(FProcessDone);
|
|
end;
|
|
|
|
procedure TForm1.TestActionExecute(Sender: TObject);
|
|
begin
|
|
TestPopup.IsOpen := TestAction.Checked;
|
|
end;
|
|
|
|
procedure TForm1.AddWorkspaceActionExecute(Sender: TObject);
|
|
begin
|
|
NewWorkspace;
|
|
end;
|
|
|
|
procedure TForm1.AlignControl(Control: TControl);
|
|
begin
|
|
var Layout := CurrLayout<TVertScrollBox>;
|
|
if Layout = nil then
|
|
exit;
|
|
|
|
Control.Parent := Layout;
|
|
Control.Width := Layout.Width;
|
|
Control.Position.Y := Layout.ChildrenRect.Bottom + 1;
|
|
Control.Anchors := [TAnchorKind.akLeft, TAnchorKind.akRight];
|
|
Control.Align := TAlignLayout.Top;
|
|
end;
|
|
|
|
procedure TForm1.Button1Click(Sender: TObject);
|
|
begin
|
|
Test1(LogMemo.Lines);
|
|
|
|
end;
|
|
|
|
procedure TForm1.Button2Click(Sender: TObject);
|
|
begin
|
|
var Symbol := SelectedSymbol;
|
|
if Symbol = '' then
|
|
exit;
|
|
|
|
var terminated := TFlag.CreateObserver(FTerminate.Signal).State;
|
|
|
|
var ticker := TConverter.CreateTicker<TDataPoint<TOhlcItem>>;
|
|
|
|
var Layout := CurrLayout<TVertScrollBox>;
|
|
if Layout = nil then
|
|
exit;
|
|
|
|
var chart1 := TMycChart.Create(Self);
|
|
AlignControl(chart1);
|
|
chart1.Height := Layout.ChildrenRect.Width * 9 / 20;
|
|
chart1.Lookback.Value := 50000;
|
|
|
|
var chart2 := TMycChart.Create(Self);
|
|
AlignControl(chart2);
|
|
chart2.Height := Layout.ChildrenRect.Width * 9 / 20;
|
|
chart2.Lookback.Value := 50000;
|
|
|
|
var equity := Strategy2.CreateStrategy2(ticker.Producer, LogMemo.Lines, chart1, chart2);
|
|
|
|
var pnlChart := TMycChart.Create(Self);
|
|
AlignControl(pnlChart);
|
|
pnlChart.Height := Layout.ChildrenRect.Width * 9 / 24;
|
|
pnlChart.Lookback.Value := 50000;
|
|
|
|
pnlChart.SetXAxisCounter<Double>(equity);
|
|
|
|
var panel := pnlChart.AddPanel;
|
|
panel.AddDoubleSeries(equity, TAlphaColors.Blue, 3);
|
|
|
|
FProcessDone := FProcessDone + (FServer as IM1FileServer).ProcessData(Symbol, terminated, ticker.Consumer);
|
|
|
|
end;
|
|
|
|
function TForm1.CreateStrategy2(Timeframe: TTimeframe): IConsumer<TDataPoint<TOhlcItem>>;
|
|
type
|
|
TSignal = record
|
|
Sig: Double;
|
|
SL: Double;
|
|
Entry: Double;
|
|
pnl: Double;
|
|
end;
|
|
var
|
|
panel: TMycChart.TPanel;
|
|
begin
|
|
var ticker := TConverter.CreateIdentity<TDataPoint<TOhlcItem>>;
|
|
Result := ticker.Consumer;
|
|
|
|
var OhlcPoint := ticker.Producer.Chain<TDataPoint<TOhlcItem>>(TTradeConverter.CreateOhlcAggregation(Timeframe));
|
|
|
|
var Ohlc := OhlcPoint.Field<TOhlcItem>('Data');
|
|
|
|
var Closes := Ohlc.Field<Double>('Close');
|
|
|
|
var Hull := Closes.Chain<Double>(THMA.CreateHMA(250)).MakeParallel;
|
|
var Sma := Closes.Chain<Double>(TSMA.CreateSMA(200)).MakeParallel;
|
|
|
|
var Lowest: Double := Double.MaxValue;
|
|
var Highest: Double := Double.MinValue;
|
|
|
|
var ATR := Ohlc.Chain<Double>(TATR.CreateATR(50)).MakeParallel;
|
|
|
|
// next stage
|
|
|
|
var curr: TSignal;
|
|
curr.SL := Double.NaN;
|
|
curr.Entry := Double.NaN;
|
|
|
|
var lastHull, lastSma: Double;
|
|
|
|
var conv := TConverter.Join<Double>(jmAll, [Ohlc.Field<Double>('Low'), Ohlc.Field<Double>('High'), Closes, ATR, Hull, Sma]);
|
|
|
|
var Signal :=
|
|
TConverter<TArray<Double>, TSignal>.CreateConverter(
|
|
function(const Values: TArray<Double>): TSignal
|
|
begin
|
|
var low := Values[0];
|
|
var high := Values[1];
|
|
var close := Values[2];
|
|
var atr := Values[3];
|
|
var hull := Values[4];
|
|
var sma := Values[5];
|
|
|
|
if low < Lowest then
|
|
Lowest := low;
|
|
if high > Highest then
|
|
Highest := high;
|
|
|
|
Result := curr;
|
|
Result.Sig := 0;
|
|
var pnl: double := NaN;
|
|
|
|
if (hull < sma) and (lastHull >= lastSma) then
|
|
begin
|
|
if curr.Sig > 0 then
|
|
pnl := close - curr.Entry;
|
|
|
|
curr.Sig := -1;
|
|
curr.SL := Highest;
|
|
curr.Entry := close;
|
|
Result := curr;
|
|
end
|
|
else if (hull > sma) and (lastHull <= lastSma) then
|
|
begin
|
|
if curr.Sig < 0 then
|
|
pnl := curr.Entry - close;
|
|
|
|
curr.Sig := 1;
|
|
curr.SL := Lowest;
|
|
curr.Entry := close;
|
|
Result := curr;
|
|
end;
|
|
|
|
atr := 15 * atr;
|
|
if curr.Sig > 0 then
|
|
begin
|
|
if close > curr.SL then
|
|
begin
|
|
if curr.SL < close - atr then
|
|
curr.SL := close - atr;
|
|
Result.SL := curr.SL;
|
|
end;
|
|
|
|
if low <= curr.SL then
|
|
begin
|
|
pnl := curr.SL - curr.Entry;
|
|
curr.Sig := 0;
|
|
Result.Sig := 0;
|
|
curr.SL := NaN;
|
|
end;
|
|
end
|
|
else if curr.Sig < 0 then
|
|
begin
|
|
if close < curr.SL then
|
|
begin
|
|
if curr.SL > close + atr then
|
|
curr.SL := close + atr;
|
|
Result.SL := curr.SL;
|
|
end;
|
|
|
|
if high >= curr.SL then
|
|
begin
|
|
pnl := curr.Entry - curr.SL;
|
|
curr.Sig := 0;
|
|
Result.Sig := 0;
|
|
curr.SL := NaN;
|
|
end;
|
|
end;
|
|
|
|
if Result.Sig <> 0 then
|
|
begin
|
|
Lowest := Double.MaxValue;
|
|
Highest := Double.MinValue;
|
|
Result.SL := Double.NaN;
|
|
Result.Entry := Double.NaN;
|
|
end;
|
|
|
|
Result.pnl := pnl;
|
|
|
|
lastHull := hull;
|
|
lastSma := sma;
|
|
end
|
|
);
|
|
|
|
conv.Chain<TSignal>(Signal);
|
|
|
|
var pnl := Signal.Producer.Field<Double>('pnl');
|
|
|
|
var FEquity: Double := 10000;
|
|
var FInit: Boolean := false;
|
|
|
|
var equity :=
|
|
TConverter<Double, Double>.CreateAggregation(
|
|
function(const Value: Double; const Broadcast: TBroadcastFunc<Double>): TState
|
|
begin
|
|
if not FInit then
|
|
begin
|
|
FInit := true;
|
|
Broadcast(FEquity);
|
|
end;
|
|
|
|
if not IsNan(Value) then
|
|
begin
|
|
FEquity := FEquity + Value;
|
|
Result := Broadcast(FEquity);
|
|
end;
|
|
end
|
|
);
|
|
|
|
pnl.Chain<Double>(equity);
|
|
|
|
var Layout := CurrLayout<TVertScrollBox>;
|
|
if Layout = nil then
|
|
exit;
|
|
|
|
var Symbol := SelectedSymbol;
|
|
if Symbol = '' then
|
|
exit;
|
|
|
|
var chart := TMycChart.Create(Self);
|
|
AlignControl(chart);
|
|
chart.Height := Layout.ChildrenRect.Width * 9 / 16;
|
|
chart.Lookback.Value := 50000;
|
|
|
|
chart.SetXAxisSeries(M15, OhlcPoint.Field<TDateTime>('Time'));
|
|
|
|
panel := chart.AddPanel;
|
|
panel.AddOhlcSeries(Ohlc);
|
|
panel.AddDoubleSeries(Hull, TAlphaColors.Cornflowerblue, 2);
|
|
panel.AddDoubleSeries(Sma, TAlphaColors.Brown, 1.5);
|
|
panel.AddDoubleSeries(Signal.Producer.Field<Double>('Entry'), TAlphaColors.Green, 1);
|
|
panel.AddDoubleSeries(Signal.Producer.Field<Double>('SL'), TAlphaColors.Red, 2);
|
|
|
|
var mean := TConverter<TArray<Double>, Double>.CreateConverter(TMean.CreateMean());
|
|
|
|
TConverter.Join<Double>(jmAll, [Hull, Sma]).Chain<Double>(mean);
|
|
|
|
panel.AddDoubleSeries(mean.Producer, TAlphaColors.Blue, 5);
|
|
|
|
var pnlChart := TMycChart.Create(Self);
|
|
AlignControl(pnlChart);
|
|
pnlChart.Height := Layout.ChildrenRect.Width * 9 / 24;
|
|
pnlChart.Lookback.Value := 50000;
|
|
|
|
pnlChart.SetXAxisCounter<Double>(equity.Producer);
|
|
|
|
////////////
|
|
|
|
(*
|
|
var Params: TEMA.TParam;
|
|
Params.Period := 20;
|
|
|
|
var indi := TEMA.CreateEMA(Params);
|
|
|
|
var EMAConv := TConverter<TEMA.TInput, TEMA.TResult>.CreateConverter(indi);
|
|
|
|
var equityEMA :=
|
|
equity
|
|
.Producer
|
|
.Chain<TEMA.TInput>(function(const Value: Double): TEMA.TInput begin Result.Price := Value end)
|
|
.Chain<TEMA.TResult>(EMAConv)
|
|
.Chain<Double>(function(const Value: TEMA.TResult): Double begin Result := Value.MA end);
|
|
*)
|
|
//////////////
|
|
|
|
panel := pnlChart.AddPanel;
|
|
panel.AddDoubleSeries(equity.Producer, TAlphaColors.Blue, 3);
|
|
// panel.AddDoubleSeries(equityEMA, TAlphaColors.Gray, 2);
|
|
|
|
/////
|
|
end;
|
|
|
|
function TForm1.CurrLayout<T>: T;
|
|
begin
|
|
if TabControl.ActiveTab = nil then
|
|
exit(nil);
|
|
|
|
var Res: T := nil;
|
|
TabControl.ActiveTab.EnumControls(
|
|
function(Control: TControl): TEnumControlsResult
|
|
begin
|
|
Result := TEnumControlsResult.Continue;
|
|
if Control is T then
|
|
begin
|
|
Res := Control as T;
|
|
Result := TEnumControlsResult.Stop;
|
|
end;
|
|
end
|
|
);
|
|
|
|
Result := Res;
|
|
end;
|
|
|
|
procedure TForm1.ExecuteStrategy(const Symbol: String; Timeframe: TTimeframe; const Consumer: IConsumer<TDataPoint<TOhlcItem>>);
|
|
begin
|
|
var terminated := TFlag.CreateObserver(FTerminate.Signal).State;
|
|
|
|
{$ifdef TICKDATA}
|
|
var ticker := TConverter.CreateTicker<TDataPoint<TTickRecord>>;
|
|
|
|
var lastPrice :=
|
|
ticker.Producer.Chain<TDataPoint<Double>>(
|
|
function(const Tick: TDataPoint<TTickRecord>): TDataPoint<Double>
|
|
begin
|
|
Result.Time := Tick.Time;
|
|
Result.Data := 0.5 * (Tick.Data.Ask + Tick.Data.Bid);
|
|
end
|
|
);
|
|
|
|
var OhlcPoint := lastPrice.Chain<TDataPoint<TOhlcItem>>(TTradeConverter.CreateTickAggregation(Timeframe));
|
|
OhlcPoint.CreateLink(Consumer);
|
|
|
|
FProcessDone := FProcessDone + (FServer as ITickFileServer).ProcessData(Symbol, terminated, ticker.Consumer);
|
|
{$else}
|
|
|
|
var ticker := TConverter.CreateTicker<TDataPoint<TOhlcItem>>;
|
|
|
|
ticker.Producer.Chain(Consumer);
|
|
|
|
FProcessDone := FProcessDone + (FServer as IM1FileServer).ProcessData(Symbol, terminated, ticker.Consumer);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TForm1.LogMemoChange(Sender: TObject);
|
|
begin
|
|
if LogMemo.Lines.Count > 1000 then
|
|
LogMemo.Lines.Clear;
|
|
end;
|
|
|
|
function TForm1.SelectedSymbol: String;
|
|
begin
|
|
Result := '';
|
|
if RandomBox.IsChecked then
|
|
Result := FSymbols.WaitFor[Random(Length(FSymbols.WaitFor))]
|
|
else if SymbolsComboBox.ItemIndex >= 0 then
|
|
Result := FSymbols.WaitFor[SymbolsComboBox.ItemIndex];
|
|
end;
|
|
|
|
procedure TForm1.StrategyButtonClick(Sender: TObject);
|
|
begin
|
|
var Layout := CurrLayout<TVertScrollBox>;
|
|
if Layout = nil then
|
|
exit;
|
|
|
|
var Symbol := SelectedSymbol;
|
|
if Symbol = '' then
|
|
exit;
|
|
|
|
var chart := TMycChart.Create(Self);
|
|
AlignControl(chart);
|
|
chart.Height := Layout.ChildrenRect.Width * 9 / 16;
|
|
chart.Lookback.Value := 50000;
|
|
|
|
/////
|
|
|
|
var timeframe := TTimeframe.H;
|
|
|
|
var ticker := TConverter.CreateIdentity<TDataPoint<TOhlcItem>>;
|
|
|
|
var OhlcPoint := ticker.Producer.Chain<TDataPoint<TOhlcItem>>(TTradeConverter.CreateOhlcAggregation(timeframe));
|
|
|
|
// var OhlcTicker := TConverter.CreateIdentity<TDataPoint<TOhlcItem>>;
|
|
// var OhlcPoint := OhlcTicker.Sender;
|
|
|
|
var Timestamps := OhlcPoint.Field<TDateTime>('Time');
|
|
var Ohlc := OhlcPoint.Field<TOhlcItem>('Data');
|
|
var Closes := Ohlc.Field<Double>('Close');
|
|
|
|
var Hull := Closes.Chain<Double>(THMA.CreateHMA(150));
|
|
var Sma := Closes.Chain<Double>(TSMA.CreateSMA(50));
|
|
var Ema := Closes.Chain<Double>(TEMA.CreateEMA(21));
|
|
var Boli := Closes.MakeParallel.Chain<TBollingerBands.TResult>(TBollingerBands.CreateBollingerBands(20, 2.0));
|
|
var Rsi := Closes.Chain<Double>(TRSI.CreateRSI(14));
|
|
var Macd := Closes.MakeParallel.Chain<TMacd.TResult>(TMACD.CreateMACD(12, 26, 9));
|
|
|
|
var Stoch := Ohlc.Chain<TStochastic.TResult>(TStochastic.CreateStochastic(14, 3));
|
|
|
|
chart.SetXAxisSeries(timeframe, Timestamps);
|
|
|
|
var Panel := chart.AddPanel;
|
|
Panel.AddOhlcSeries(Ohlc);
|
|
Panel.AddDoubleSeries(Hull, TAlphaColors.Aliceblue);
|
|
Panel.AddDoubleSeries(Sma, TAlphaColors.Yellow);
|
|
Panel.AddDoubleSeries(Ema, TAlphaColors.Aqua);
|
|
Panel.AddDoubleSeries(Boli.Field<Double>('UpperBand'), TAlphaColors.Gray);
|
|
Panel.AddDoubleSeries(Boli.Field<Double>('MiddleBand'), TAlphaColors.Darkgray, 1.0);
|
|
Panel.AddDoubleSeries(Boli.Field<Double>('LowerBand'), TAlphaColors.Gray);
|
|
|
|
Panel := chart.AddPanel;
|
|
Panel.AddDoubleSeries(Rsi, TAlphaColors.Fuchsia);
|
|
|
|
Panel := chart.AddPanel;
|
|
Panel.AddDoubleSeries(Macd.Field<Double>('MacdLine'), TAlphaColors.Orange);
|
|
Panel.AddDoubleSeries(Macd.Field<Double>('SignalLine'), TAlphaColors.Dodgerblue);
|
|
Panel.AddDoubleSeries(Macd.Field<Double>('Histogram'), TAlphaColors.Lightgreen);
|
|
|
|
Panel := chart.AddPanel;
|
|
Panel.AddDoubleSeries(Stoch.Field<Double>('K'), TAlphaColors.Green);
|
|
Panel.AddDoubleSeries(Stoch.Field<Double>('D'), TAlphaColors.Red);
|
|
|
|
/////
|
|
{
|
|
var tickChart := TMycChart.Create(Self);
|
|
tickChart.Height := Layout.ChildrenRect.Width * 9 / 16;
|
|
AlignControl(tickChart);
|
|
tickChart.Lookback.Value := 1000000;
|
|
|
|
var TickTime := ticker.Field<TDateTime>('Time');
|
|
|
|
var TickData := ticker.Field<TAskBidItem>('Data');
|
|
var TickAsk := TickData.Field<Double>('Ask');
|
|
var TickBid := TickData.Field<Double>('Bid');
|
|
|
|
var TickSpread := TickData.Chain<Double>(function(const Tick: TAskBidItem): Double begin Result := Tick.Bid - Tick.Ask; end);
|
|
|
|
tickChart.SetXAxisSeries(TTimeframe.S, TickTime.Sender);
|
|
panel := tickChart.AddPanel;
|
|
panel.AddDoubleSeries(TickAsk.Sender, TAlphaColors.Blue);
|
|
panel.AddDoubleSeries(TickBid.Sender, TAlphaColors.Red);
|
|
|
|
panel := tickChart.AddPanel;
|
|
panel.AddDoubleSeries(TickSpread.Sender);
|
|
}
|
|
/////
|
|
|
|
ExecuteStrategy(Symbol, timeframe, ticker.Consumer);
|
|
end;
|
|
|
|
procedure TForm1.Strat2ButtonClick(Sender: TObject);
|
|
begin
|
|
var Symbol := SelectedSymbol;
|
|
if Symbol = '' then
|
|
exit;
|
|
|
|
var timeframe := TTimeframe.M15;
|
|
// ExecuteStrategy(Symbol, timeframe, CreateStrategy2(timeframe));
|
|
|
|
var tstStrat := StrategyTest.CreateStrategy1(timeframe);
|
|
|
|
ExecuteStrategy(Symbol, timeframe, tstStrat.Consumer);
|
|
|
|
var Layout := CurrLayout<TVertScrollBox>;
|
|
if Layout = nil then
|
|
exit;
|
|
|
|
var pnlChart := TMycChart.Create(Self);
|
|
AlignControl(pnlChart);
|
|
pnlChart.Height := Layout.ChildrenRect.Width * 9 / 24;
|
|
pnlChart.Lookback.Value := 50000;
|
|
|
|
pnlChart.SetXAxisCounter<Double>(tstStrat.Producer);
|
|
|
|
var panel := pnlChart.AddPanel;
|
|
panel.AddDoubleSeries(tstStrat.Producer, TAlphaColors.Blue, 3);
|
|
end;
|
|
|
|
end.
|