LoginSignup
0

posted at

updated at

【v39】テクニカル指標からイベントトリガーを発火する

はじめに

過去記事は「auカブコム証券のkabuステーションREST APIに関する記事一覧」。

ようやくいろいろ計算したテクニカル指標をチェックして、イベントトリガーを発火してみようかと。

ゴール

骨組みを作るため、条件に一致したら、文字列でずらずらファイルに書き込む。
最初にバッチ用ツールを作成し、後からリアルタイムログからメモリ上で連携させる。

ベースとなるソース

v38(r10)をそのまま使える以下のクラスそのまま使い、新たにv39(r11)を作成する。

  • v38.factory.BarNameFactory_r10
  • v38.bean.MergeChartInfo_r10

パッケージ構成

v38と同様にファクトリーを用意して、以下のサブパッケージに分ける。

  • bean: エンティティ
  • factory: プラグインインスタンス生成の管理
  • i: インターフェイス
  • t: イベントトリガープラグイン

実装

propertiesファイル

CalcIndicatorFactory_r10.propertiesとほぼ同じプロパティファイルを用意し、動的にクラスロードする。

1=v39.t.TriggerIndicator1_r11
2=v39.t.TriggerIndicator2_r11
3=v39.t.TriggerIndicator3_r11
4=v39.t.TriggerIndicator4_r11
5=v39.t.TriggerIndicator5_r11
6=v39.t.TriggerIndicator6_r11
7=v39.t.TriggerIndicator7_r11

クラスの対応

テクニカル指標を計算するクラス構成と、テクニカル指標をチェックするクラス構成をほぼ同じように作成する。

  • MainCalcIndicator_r10 -> MainTriggerIndicator_r11
  • CalcCoordinator_r10 -> TriggerCoordinator_r11
  • CalcIndicatorFactory_r10 -> TriggerIndicatorFactory_r11
  • CalcIndicatorCommon_r10 -> TriggerIndicatorCommon_r11
  • CalcIndicator_r10 -> TriggerIndicator_r11
  • CalcIndicator1_r10 -> TriggerIndicator1_r11
  • CalcIndicator?_r10 -> TriggerIndicator?_r11

ファイルの入出力

もともとCalcIndicator1m_1.outのようなファイルはstdoutに大量に出すと内容が確認できなくなるため、足名+種別ごとに分けてファイル保存していたが、とりあえず全レコードのカラム数が固定のCSVファイルなので、これを読み込む。

後からリアルタイム用ツールに連携する際に、何とかファイル保存するList indicatorListを持ってくる。

チェックロジック

とりあえずSMA5,SMA25,SMA75で、ゴールデンクロス、デッドクロスの判定を作ってみる。

	protected void checkIndicator() {
		for (int i = 1; i < indicatorList.size(); i++) {
			TriggerIndicatorInfo_r11 tii1 = indicatorList.get(i);
			TriggerIndicatorInfo_r11 tii0 = indicatorList.get(i - 1);
			String date = tii1.date;
			double mean11 = tii1.values[0];
			double mean10 = tii0.values[0];
			double mean21 = tii1.values[1];
			double mean20 = tii0.values[1];
			double mean31 = tii1.values[2];
			double mean30 = tii0.values[2];
			if (mean10 < mean20 && mean11 > mean21) {
				String msg = String.format("[%s] GC SMA5  > SMA25 (%.2f %.2f)->(%.2f %.2f)", date, mean10, mean20, mean11, mean21);
				reportList.add(msg);
			}
			if (mean10 > mean20 && mean11 < mean21) {
				String msg = String.format("[%s] DC SMA5  < SMA25 (%.2f %.2f)->(%.2f %.2f)", date, mean10, mean20, mean11, mean21);
				reportList.add(msg);
			}
			if (mean20 < mean30 && mean21 > mean31) {
				String msg = String.format("[%s] GC SMA25 > SMA75 (%.2f %.2f)->(%.2f %.2f)", date, mean20, mean30, mean21, mean31);
				reportList.add(msg);
			}
			if (mean20 > mean30 && mean21 < mean31) {
				String msg = String.format("[%s] DC SMA25 < SMA75 (%.2f %.2f)->(%.2f %.2f)", date, mean20, mean30, mean21, mean31);
				reportList.add(msg);
			}
			if (mean10 < mean30 && mean11 > mean31) {
				String msg = String.format("[%s] GC SMA5  > SMA75 (%.2f %.2f)->(%.2f %.2f)", date, mean10, mean30, mean11, mean31);
				reportList.add(msg);
			}
			if (mean10 > mean30 && mean11 < mean31) {
				String msg = String.format("[%s] DC SMA5  < SMA75 (%.2f %.2f)->(%.2f %.2f)", date, mean10, mean30, mean11, mean31);
				reportList.add(msg);
			}
		}
	}

テスト

実行すると、XXX_1.outに出力されているものがあるようだ。

TriggerCoordinator_r11.readChartData(): /tmp/chart/167110019_F202211/ChartData1m_r10.txt, chartList.size=1203
TriggerIndicatorCommon_r11.readIndicatorData(): /tmp/chart/167110019_F202211/CalcIndicator1m_1.out, indicatorList.size=60
TriggerIndicatorCommon_r11.printEvent(): /tmp/chart/167110019_F202211/TriggerIndicator1m_1.out, writeCnt=3
TriggerIndicatorCommon_r11.readIndicatorData(): /tmp/chart/167110019_F202211/CalcIndicator1m_2.out, indicatorList.size=60
TriggerIndicatorCommon_r11.printEvent(): /tmp/chart/167110019_F202211/TriggerIndicator1m_2.out, writeCnt=0
TriggerIndicatorCommon_r11.readIndicatorData(): /tmp/chart/167110019_F202211/CalcIndicator1m_3.out, indicatorList.size=60
TriggerIndicatorCommon_r11.printEvent(): /tmp/chart/167110019_F202211/TriggerIndicator1m_3.out, writeCnt=0
TriggerIndicatorCommon_r11.readIndicatorData(): /tmp/chart/167110019_F202211/CalcIndicator1m_4.out, indicatorList.size=60
TriggerIndicatorCommon_r11.printEvent(): /tmp/chart/167110019_F202211/TriggerIndicator1m_4.out, writeCnt=0
TriggerIndicatorCommon_r11.readIndicatorData(): /tmp/chart/167110019_F202211/CalcIndicator1m_5.out, indicatorList.size=60
TriggerIndicatorCommon_r11.printEvent(): /tmp/chart/167110019_F202211/TriggerIndicator1m_5.out, writeCnt=0
TriggerIndicatorCommon_r11.readIndicatorData(): /tmp/chart/167110019_F202211/CalcIndicator1m_6.out, indicatorList.size=60
TriggerIndicatorCommon_r11.printEvent(): /tmp/chart/167110019_F202211/TriggerIndicator1m_6.out, writeCnt=0
TriggerIndicatorCommon_r11.readIndicatorData(): /tmp/chart/167110019_F202211/CalcIndicator1m_7.out, indicatorList.size=60
TriggerIndicatorCommon_r11.printEvent(): /tmp/chart/167110019_F202211/TriggerIndicator1m_7.out, writeCnt=0
TriggerCoordinator_r11.readChartData(): /tmp/chart/167110019_F202211/ChartData3m_r10.txt, chartList.size=403
TriggerIndicatorCommon_r11.readIndicatorData(): /tmp/chart/167110019_F202211/CalcIndicator3m_1.out, indicatorList.size=60
TriggerIndicatorCommon_r11.printEvent(): /tmp/chart/167110019_F202211/TriggerIndicator3m_1.out, writeCnt=9

ファイルサイズが0バイト超のファイルを開くと、それらしきメッセージが保存されている。

2022/10/06 02:14:00.555 [2022/09/24 03:12:00] GC SMA25 > SMA75 (26370.40 26372.00)->(26372.20 26371.27)
2022/10/06 02:14:00.555 [2022/09/24 03:12:00] GC SMA5  > SMA75 (26368.00 26372.00)->(26372.00 26371.27)
2022/10/06 02:14:00.555 [2022/09/24 03:15:00] GC SMA5  > SMA25 (26372.00 26372.20)->(26376.00 26373.20)
2022/10/06 02:14:00.555 [2022/09/24 03:18:00] DC SMA5  < SMA25 (26376.00 26373.20)->(26363.00 26369.20)
2022/10/06 02:14:00.555 [2022/09/24 03:18:00] DC SMA5  < SMA75 (26376.00 26370.53)->(26363.00 26368.93)
2022/10/06 02:14:00.556 [2022/09/24 03:21:00] DC SMA25 < SMA75 (26369.20 26368.93)->(26366.80 26367.60)
2022/10/06 02:14:00.556 [2022/09/24 04:15:00] GC SMA5  > SMA25 (26320.00 26329.80)->(26334.00 26329.40)
2022/10/06 02:14:00.556 [2022/09/24 04:27:00] GC SMA5  > SMA75 (26337.00 26340.93)->(26344.00 26340.07)
2022/10/06 02:14:00.556 [2022/09/24 04:54:00] GC SMA25 > SMA75 (26339.80 26341.87)->(26343.60 26343.00)

今後

2から7まで同様にチェックを作れば何かでるはず。
足名+種別ごとにファイルが分かれると大変なので、List reportListをクラスのリストにして、メタ情報を持たせて、もっと手前のクラスでマージ&ソートしてファイル出力したい。

追記:IndicatorCodeによる紐づけ(v39)

マージツールとテクニカル指標計算ツールを統合するで追加した「IndicatorCodeによる紐づけ」をこちらにも反映する。
列挙体はv38.factory.IndicatorCodeを参照し、具象クラス内に埋め込む。

public abstract class TriggerIndicatorCommon_r11 implements TriggerIndicator_r11 {
	abstract public IndicatorCode getCode();
public class TriggerIndicator1_r11 extends TriggerIndicatorCommon_r11 implements TriggerIndicator_r11 {
	public IndicatorCode getCode() {
		return IndicatorCode.SMA;
	}

追記:リアルタイムログ監視ツール

v38.MainWatchChartData_r10をベースに、v39.MainWatchChartData_r11を追加する。

			List<String> lines = pollingCsvChartData();
			for (String key : BarNameFactory_r10.getBarNames()) {
				MergeChartData_r10 merge = mergeMap.get(key);
				merge.mergeCsvChartData(lines);
//				merge.writeChartMap();
				CalcCoordinator_r10 calc = calcMap.get(key);
				calc.execute(merge);
			}

			List<String> lines = pollingCsvChartData();
			for (String key : BarNameFactory_r10.getBarNames()) {
				MergeChartData_r10 merge = mergeMap.get(key);
				merge.mergeCsvChartData(lines);
//				merge.writeChartMap();
				CalcCoordinator_r10 calc = calcMap.get(key);
				calc.execute(merge);
				TriggerCoordinator_r11 trigger = triggerMap.get(key);
				trigger.execute(merge, calc);
			}

v39.TriggerCoordinator_r11にメソッド追加。その他readChartData(MergeChartData_r10)なども追加。

	public void execute() {
		readChartData();
		for (TriggerIndicator_r11 ti : triggerList) {
			ti.execute(chartList);
		}
	}

	public void execute(MergeChartData_r10 merge, CalcCoordinator_r10 calc) {
		readChartData(merge);
		Map<Integer, CalcIndicator_r10> calcMap = calc.getCalcMap();
		for (TriggerIndicator_r11 ti : triggerList) {
			CalcIndicator_r10 ci = calcMap.get(ti.getCode().intValue());
			ti.execute(chartList, ci);
		}
	}

v39.TriggerIndicatorCommon_r11にメソッド追加。その他readIndicatorData(CalcIndicator_r10)なども追加。

	public void execute(List<MergeChartInfo_r10> chartList) {
		this.chartList = chartList;
		reportList.clear();
		readIndicatorData();
		try (PrintWriter pw = FileUtil.writer(outFilePath, FileUtil.UTF8)) {
			checkIndicator();
			printEvent(pw);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void execute(List<MergeChartInfo_r10> chartList, CalcIndicator_r10 ci) {
		this.chartList = chartList;
		reportList.clear();
		readIndicatorData(ci);
		try (PrintWriter pw = FileUtil.writer(outFilePath, FileUtil.UTF8)) {
			checkIndicator();
			printEvent(pw);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

実行結果

2022/10/06 08:09:14.328 [2022/10/04 04:03:00] DC SMA5  < SMA25 (26691.00 26688.60)->(26685.00 26688.60)
2022/10/06 08:09:14.328 [2022/10/04 04:16:00] DC SMA5  < SMA75 (26665.00 26663.73)->(26661.00 26664.27)
2022/10/06 08:09:14.328 [2022/10/04 04:25:00] GC SMA5  > SMA25 (26667.00 26671.20)->(26672.00 26670.80)
2022/10/06 08:09:14.328 [2022/10/04 04:25:00] GC SMA5  > SMA75 (26667.00 26668.60)->(26672.00 26669.33)
2022/10/06 08:09:14.328 [2022/10/04 04:28:00] DC SMA25 < SMA75 (26671.00 26670.73)->(26671.00 26671.33)
2022/10/06 08:09:14.328 [2022/10/04 04:33:00] DC SMA5  < SMA75 (26674.00 26673.27)->(26671.00 26673.67)
2022/10/06 08:09:14.328 [2022/10/04 04:35:00] DC SMA5  < SMA25 (26671.00 26668.80)->(26667.00 26667.60)
↓
2022/10/06 08:09:43.967 [2022/10/04 04:03:00] DC SMA5  < SMA25 (26691.00 26688.60)->(26685.00 26688.60)
2022/10/06 08:09:43.967 [2022/10/04 04:16:00] DC SMA5  < SMA75 (26665.00 26663.73)->(26661.00 26664.27)
2022/10/06 08:09:43.967 [2022/10/04 04:25:00] GC SMA5  > SMA25 (26667.00 26671.20)->(26672.00 26670.80)
2022/10/06 08:09:43.967 [2022/10/04 04:25:00] GC SMA5  > SMA75 (26667.00 26668.60)->(26672.00 26669.33)
2022/10/06 08:09:43.967 [2022/10/04 04:28:00] DC SMA25 < SMA75 (26671.00 26670.73)->(26671.00 26671.33)
2022/10/06 08:09:43.967 [2022/10/04 04:33:00] DC SMA5  < SMA75 (26674.00 26673.27)->(26671.00 26673.67)
2022/10/06 08:09:43.967 [2022/10/04 04:35:00] DC SMA5  < SMA25 (26671.00 26668.80)->(26667.00 26667.60)

毎回ファイル上書きするので、ファイルサイズや件数は変わらないが、極めて効率が悪いので、v40で出力データに主キーを設定し、前回からの差分でファイル追記できるようにする。

追記:転換点イベントトリガー

テクニカル指標として転換点を追加したので、イベントトリガーも追加する。

追記:イベントトリガー情報を定義

List<String> reportListをList<EventInfo> eventListに置き換える。
reportListの文字列の前に現時刻のタイムスタンプをつけていたので、EventInfoへ現時刻を追加する。

現時点で8カラムを定義する。
IDは、Name, Bar, Indicator, Dateを元に生成される。
CreateDateは、メソッド呼び出し時の時刻を使用する。

No Name Description Example
1 ID ユニークID 9005_1m_1_20221007_140700_DC
2 CreateDate 登録日時 2022/10/22 08:44:11.567
3 Name ディレクトリ名(銘柄コード) 9005
4 Bar 足名 1m
5 Indicator テクニカル指標の種別 1
6 Date 発生日時 2022/10/07 14:07:00
7 type トリガー種別 GC
8 Report レポート本文 SMA5 < SMA25 (1723.00 1722.80)->(1722.60 1722.80)

無条件にListへ追加しているが、将来IDでユニークとなるように制約をかける。

追記:TriggerIndicatorInfo_r11をv39.beanからbeanに移動

MergeChartInfo_r10やCalcIndicatorInfo_r10と同様にTriggerIndicatorInfo_r11もbeanへ移動する。
v39.bean.EventInfoは、項目を追加する可能性があるため、パッケージを移動せずに、EventInfo_r11に変更する。

追記:TriggerCoordinator_r11のマージデータ受け入れをMergeChartData_r10からMapに変更

execute(MergeChartData_r10, CalcCoordinator_r10)を後から追加して、MainWatchChartDataでマージ後のデータを受け渡していたが、インターフェイスを渡すと、revが上がっていくと、どちらも上げていく必要がある。最終的にreadChartData()の中で、getChartMap()で全データを取得するので、MainWatchChartDataがgetChartMap()を呼んで、Mapを渡す。

本来ならば、MergeChartInfo_r10をMap, Listなどで管理するクラスがあった方がよい。

追記:ソースをarchiveブランチへ移動

最新版に移行し、もう使われることはないので、アーカイブする。

githubソース

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0