人工ニューラルネットワークで株価予測 ~Delphiソースコード集

人工ニューラルネットワークで株価予測 ~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個をフォームへドラッグ&ドロップします。

Delphiで人工ニューラルネットワーク(Artificial Neural Network)を使用する

「ファイル」⇒「全て保存」でフォルダを作成して、プロジェクトとユニットを保存します。
プロジェクトフォルダ内に「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を「回帰問題」として学習します。学習が完了するまでしばらく(長ければ数分)時間がかかります。

Delphiで人工ニューラルネットワーク(Artificial Neural Network)を使用し日経平均株価終値を「回帰問題」として学習します

次にButton2をクリックすると、2022/11以降の翌日、翌々日の日経平均株価終値を予想してグラフ表示します。

Delphiで人工ニューラルネットワーク(Artificial Neural Network)を使用し日経平均株価終値を予測する

次にButton3をクリックすると、全期間の翌日、翌々日の日経平均株価終値を予想してグラフ表示します。

Delphiで人工ニューラルネットワーク(Artificial Neural Network)を使用し日経平均株価終値を予測する