人工ニューラルネットワークで株価予測 ~Delphiソースコード集
連続する7営業日の日経平均株価終値から、翌日、翌々日の日経平均株価終値を予想するプログラムを作成します。
人工ニューラルネットワーク(Artificial Neural Network)を使用する為のファイルの準備
本ホームページのhttps://mam-mam.net/delphi/ann.htmlから
「UMamAnn.pas」ソースコード用意しプロジェクトフォルダ内に保存します。
また、
https://indexes.nikkei.co.jp/nkave/index?type=download
から「日経平均株価」⇒「日次データ」をダウンロード(nikkei_stock_average_daily_jp.csv)してプロジェクトフォルダに入ます。
Delphiを起動して新規作成を行い、必要なコンポーネントをドラッグ&ドロップする
Delphi起動⇒ファイル⇒新規作成⇒WindowsVCLアプリケーション を選択します。
TButton×3個、TMemo×1個、TChart×1個をフォームへドラッグ&ドロップします。
「ファイル」⇒「全て保存」でフォルダを作成して、プロジェクトとユニットを保存します。
プロジェクトフォルダ内に「UMamAnn.pas」ファイルと「nikkei_stock_average_daily_jp.csv」ファイルを配置します。
ソースコードを記述する
Form1のOnCreateイベント、Form1のOnDestroyイベント、Button1のOnClickイベント、Button2のOnClickイベント、Button3のOnClickイベントに以下ソースコードを記述します。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
VclTee.TeeGDIPlus, VCLTee.TeEngine,
VCLTee.TeeProcs, VCLTee.Chart, VCLTee.Series
,UMamAnn;
type
//CSVファイルから日経平均株価終値を読んで入れる構造体
TData=Record
dt:TDateTime;//日付
EndV:Single; //日経平均株価終値
End;
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Memo1: TMemo;
Chart1: TChart;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
//0~35000を0.0[15000]~1.0[35000]に正規化
function normalize(s:Single):Single;
//0.0[15000]~1.0[35000]を0~35000に戻す
function renormalize(s:Single):Single;
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
Ann:TMamAnn;
Layers:TArray<Integer>;
il,ol:integer;//入力層と出力層のニューロン数
data:TArray<TData>;//CSVファイルを読んで入れる配列
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var dt:string;
i,j:Integer;
ip,op:TArray<Single>;
epoch:Integer;
begin
//学習
SetLength(ip,il);
SetLength(op,ol);
//繰り返し400回学習する
for epoch := 1 to 400 do
begin
i:=0;
dt:='';
while dt<='2022/10/31' do //2022年10月31日までを学習させる
begin
for j := 0 to il-1 do
begin
ip[j]:=(data[i+j].EndV);
end;
for j := 0 to ol-1 do
begin
op[j]:=data[i+il+j].EndV;
end;
dt:=FormatDateTime('YYYY/MM/DD',data[i+il+ol-1].dt);//日付を文字列で取得
//学習する
Ann.Train(ip,op);
inc(i);
end;
end;
Memo1.Lines.Add(Format('学習完了 MSE=%6.4f',[Ann.GetMSE]));
end;
procedure TForm1.Button2Click(Sender: TObject);
var dt1,dt2:TDateTime;
l,i,j:Integer;
ip,op:TArray<Single>;
pre1,pre2:Single;//予測値(翌営業日、翌々営業日)
fact1:Single;//実際の値
begin
//全期間の予測
Chart1.Series[0].Clear;
Chart1.Series[1].Clear;
Chart1.Series[2].Clear;
SetLength(ip,il);//指定日を含む過去7営業日の日経平均株価の終値を入れる
SetLength(op,ol);//指定日から翌日、翌々日の日経平均株価の終値を入れる
l:=0;//2022/11/01を探す
for i := Low(data) to High(data) do
begin
if FormatDateTime('YYYYMMDD',data[i].dt)='20221101' then
begin
l:=i;
break;
end;
end;
//2022/11/01以降をAIに予測させる
for i := l-il to High(data)-il-ol do
begin
for j := 0 to il-1 do
begin
ip[j]:=(data[i+j].EndV);//-9営業日の終値
end;
Ann.Run(ip,op);//翌営業日と翌々営業日の予測
pre1:=renormalize(op[0]);
pre2:=renormalize(op[1]);
//翌営業日
dt1:=data[i+il+0].dt; //日付
fact1:=renormalize(data[i+il+0].EndV); //実際の値
dt2:=data[i+il+1].dt; //日付
Chart1.Series[0].AddXY(
dt1,fact1
);
Chart1.Series[1].AddXY(
dt1,pre1
);
Chart1.Series[2].AddXY(
dt2,pre2
);
end;
Memo1.Lines.Add('2022/11/01以降の予測');
end;
procedure TForm1.Button3Click(Sender: TObject);
var dt1,dt2:TDateTime;
i,j:Integer;
ip,op:TArray<Single>;
pre1,pre2:Single;//予測値(翌営業日、翌々営業日)
fact1:Single;//実際の値
begin
//全期間の予測
Chart1.Series[0].Clear;
Chart1.Series[1].Clear;
Chart1.Series[2].Clear;
SetLength(ip,il);//指定日を含む過去7営業日の日経平均株価の終値を入れる
SetLength(op,ol);//指定日から翌日、翌々日の日経平均株価の終値を入れる
//全期間AIに予測させる
for i := Low(data) to High(data)-il-ol do
begin
for j := 0 to il-1 do
begin
ip[j]:=(data[i+j].EndV);//-9営業日の終値
end;
Ann.Run(ip,op);//翌営業日と翌々営業日の予測
pre1:=renormalize(op[0]);
pre2:=renormalize(op[1]);
//翌営業日
dt1:=data[i+il+0].dt; //日付
fact1:=renormalize(data[i+il+0].EndV); //実際の値
dt2:=data[i+il+1].dt; //日付
Chart1.Series[0].AddXY(
dt1,fact1
);
Chart1.Series[1].AddXY(
dt1,pre1
);
Chart1.Series[2].AddXY(
dt2,pre2
);
end;
Memo1.Lines.Add('全期間の予測');
end;
procedure TForm1.FormCreate(Sender: TObject);
var LineSeries1,LineSeries2,LineSeries3:TLineSeries;//折れ線グラフ系列1,2,3
stl1,stl2:TStringList;
i:Integer;
begin
il:=7;
ol:=2;
SetLength(Layers,4);//4層
Layers[0]:=il; //入力層7ニューロン(連続する7営業日の日経平均株価終値)
Layers[1]:=7; //中間層7ニューロン
Layers[2]:=3; //中間層3ニューロン
Layers[3]:=ol; //出力層2ニューロン(翌日、翌々日の日経平均株価終値の予想値)
Ann:=TMamAnn.Create(Layers,0.005);//学習率0.005
LineSeries1:=TLineSeries.Create(Chart1);
LineSeries2:=TLineSeries.Create(Chart1);
LineSeries3:=TLineSeries.Create(Chart1);
Chart1.Title.Caption:='日経平均株価終値の予測';
Chart1.AddSeries(LineSeries1);
Chart1.AddSeries(LineSeries2);
Chart1.AddSeries(LineSeries3);
Chart1.Series[0].XValues.DateTime:=True;
Chart1.Series[1].XValues.DateTime:=True;
Chart1.Series[2].XValues.DateTime:=True;
Chart1.Series[0].Pen.Width:=4;
Chart1.Series[1].Pen.Width:=4;
Chart1.Series[2].Pen.Width:=1;
Chart1.Series[0].Title:='日経平均株価終値';
Chart1.Series[1].Title:='翌営業日予測値';
Chart1.Series[2].Title:='翌々営業日予測値';
Chart1.BottomAxis.DateTimeFormat:='yyyy年mm月dd日';
Chart1.BottomAxis.LabelsAngle:=90;
//Chart1.BottomAxis.LabelsFont.Size:=10;
Chart1.View3D:=False;
Chart1.LeftAxis.AutomaticMaximum:=true;
Chart1.LeftAxis.AutomaticMinimum:=true;
//https://indexes.nikkei.co.jp/nkave/index?type=download
//から「日経平均株価」⇒「日次データ」を
//ダウンロード(nikkei_stock_average_daily_jp.csv)して
//プロジェクトフォルダに入れておく
stl1:=TStringList.Create;
stl2:=TStringList.Create;
try
stl2.Delimiter:=',';
stl2.StrictDelimiter:=True;
stl2.QuoteChar:='"';
stl1.LoadFromFile('..\..\nikkei_stock_average_daily_jp.csv');
stl1.Sort;
SetLength(data , stl1.Count-2);
for i := 0 to stl1.Count-3 do
begin
//日付,終値,始値,高値,安値 の順番に入っている
stl2.DelimitedText:=stl1[i];
data[i].dt:=StrToDateTime(
StringReplace(stl2[0],'-','/',[rfReplaceAll])
);
data[i].EndV:=normalize(
StrToFloat(StringReplace(stl2[1],',','',[rfReplaceAll]))
);
end;
finally
stl1.Free;
stl2.Free;
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Ann.Free;
end;
function TForm1.normalize(s: Single): Single;
begin
//0~35000を0.0[15000]~1.0[35000]に正規化
result:=(s-15000)/20000;
end;
function TForm1.renormalize(s: Single): Single;
begin
//0.0(15000)~1.0(35000)を0~35000に戻す
result:=s*20000+15000;
end;
end.
実行する
実行ボタンを押して実行します。(デバッグ実行でもOK)
Button1をクリックすると、日経平均株価終値の2019/01~2022/10を「回帰問題」として学習します。学習が完了するまでしばらく(長ければ数分)時間がかかります。
次にButton2をクリックすると、2022/11以降の翌日、翌々日の日経平均株価終値を予想してグラフ表示します。
次にButton3をクリックすると、全期間の翌日、翌々日の日経平均株価終値を予想してグラフ表示します。
