見出し画像

アノマリーを全探索したかった

モチベーションは、以前に話題になってた日曜アノマリー。

一つの時系列からアノマリーを調べるコードを実装しました。
複数の時系列で全探索できるようにできたら良かったけどやらなかった。

日足で実行すれば日曜アノマリーが発見できます。
(月~土vs日 の相関が高い場合は、nx=6, ny=1, steps=7, offset=データ次第みたいなパラメータが発見できると思います)

いろんな区間のopenからcloseまでのリターンで調べてます。

あと探索範囲広げると時間かかります。
C++で書き直したコードがあるんですけどどっかにいきました。

使い方とかの説明がめんどくさいのでソースコード読んでいただけると助かります。

ソースコード

import pandas as pd
from scipy.stats import spearmanr
from tqdm import tqdm

def anomaly_ic(ohlcv, nx=1, ny=1, step=1, offset=0):
	open = ohlcv['open'].values
	close = ohlcv['close'].values
	x, y = [], []
	for i in range(offset, len(ohlcv)-nx-ny+1, step):
		x.append(close[i+nx-1]/open[i]-1)
		y.append(close[i+nx+ny-1]/open[i+nx]-1)
	return spearmanr(x, y)[0], len(x), x, y

def discover_anomaly(ohlcv, nxs=range(1, 11), nys=range(1, 4), steps=range(1, 8), offsets=range(7)):
	result = pd.DataFrame(columns=['ic', 'n', 'nx', 'ny', 'step', 'offset'])
	pbar = tqdm(total=len(nxs) * len(nys) * len(steps) * len(offsets))
	for nx in nxs:
		for ny in nys:
			for step in steps:
				for offset in offsets:
					ic, n, x, y = anomaly_ic(ohlcv, nx, ny, step, offset)
					result = result.append({'ic': ic, 'n': n, 'nx': nx, 'ny': ny, 'step': step, 'offset': offset}, ignore_index=True)
					pbar.update()
	pbar.close()
	return result.sort_values('ic', ascending=False).reset_index(drop=True)


1日足だとこんな感じで見つけられます。


1分足だと計算時間的に探索範囲広げるのきつい。
データ数少なめにすればいいかもだけど。
1分足だと24horizonとか見つかるかもしれない。(やってない)


データ・マイニング(過去のデータを計量的にうまく加工して表面上のパフォーマンスをうまくみせること)につながる可能性が高い。



C++のコードありました。
Spearmanの相関係数の実装の仕方を適当に調べてもいまいちわからなかったからPearsonの相関係数になってます。

コンパイラオプションの-O3とかつけるとめちゃ高速になります。

 #include <iostream> #include <fstream> #include <sstream> #include <cstdio> #include <vector> #include <tuple> #include <cmath> #include <algorithm>

using namespace std;

double corrcoef(vector<double> &x, vector<double> &y){
    int n = x.size();
    double sum_x = 0, sum_y = 0, sum_xy = 0;
    double squaresum_x = 0, squaresum_y = 0;
    for (int i = 0; i < n; i++){
        sum_x += x[i];
        sum_y += y[i];
        sum_xy += x[i] * y[i];
        squaresum_x += x[i] * x[i];
        squaresum_y += y[i] * y[i];
    }
    double corr = (double)(n * sum_xy - sum_x * sum_y) / sqrt((n * squaresum_x - sum_x * sum_x) * (n * squaresum_y - sum_y * sum_y));
    return corr;
}

tuple<double, int> anomaly_ic(const vector<double> &op, const vector<double> &cl, const int nx, const int ny, const int step, const int offset){
	vector<double> x, y;
	x.resize((op.size()-nx-ny-offset+step)/step);
	y.resize((op.size()-nx-ny-offset+step)/step);
	double ic;
	int n = op.size();
	for(int i = offset, cnt = 0; i < n-nx-ny+1; i += step, ++cnt){
		x[cnt] = cl[i+nx-1]/op[i]-1;
		y[cnt] = cl[i+nx+ny-1]/op[i+nx]-1;
	}
	ic = corrcoef(x, y);
	return make_tuple(ic, x.size());
}

vector<tuple<double, int, int, int, int, int>> discover_anomaly(const vector<double> &op, const vector<double> &cl, const vector<int> &nxs, const vector<int> &nys, const vector<int> &steps, const vector<int> &offsets){
	vector<tuple<double, int, int, int, int, int>> results;
	results.resize(nxs.size() * nys.size() * steps.size() * offsets.size());
	tuple<double, int> result;
	int cnt = 0;
	int nxs_size = nxs.size(), nys_size = nys.size(), steps_size = steps.size(), offsets_size = offsets.size();
	for(int i = 0; i < nxs_size; ++i){
		for(int j = 0; j < nys_size; ++j){
			for(int k = 0; k < steps_size; ++k){
				for(int l = 0; l < offsets_size; ++l){
					result = anomaly_ic(op, cl, nxs[i], nys[j], steps[k], offsets[l]);
					results[cnt] = make_tuple(get<0>(result), get<1>(result), nxs[i], nys[j], steps[k], offsets[l]);
					++cnt;
				}
			}
		}
	}
	return results;
}

int main(){
	int column_no;
	double f;
	string cell;
	string line;
	string csv_path = "./ohlcv.csv";
	ifstream ifs(csv_path);
	vector<double> op, cl;

	while (getline(ifs, line)) {    
		istringstream i_stream(line);
		column_no = 0;
		while (getline(i_stream, cell, ',')){
			if(column_no == 1){
				sscanf(cell.c_str(), "%f", &f);
				op.push_back(f);
			}
			else if(column_no == 4){
				sscanf(cell.c_str(), "%f", &f);
				cl.push_back(f);
			}
			column_no++;
		}
	}

	vector<int> nxs;
	for(int i = 1; i <= 60; ++i) nxs.push_back(i);

	vector<int> nys;
	for(int i = 1; i <= 60; ++i) nys.push_back(i);

	vector<int> steps;
	for(int i = 1; i <= 60; ++i) steps.push_back(i);

	vector<int> offsets;
	for(int i = 0; i <= 60; ++i) offsets.push_back(i);

	vector<tuple<double, int, int, int, int, int>> results = discover_anomaly(op, cl, nxs, nys, steps, offsets);
	sort(results.begin(), results.end());

	for(int i = 0; i < results.size(); ++i){
		printf("IC=%.4f N=%d nx=%d ny=%d step=%d offset=%d\n", get<0>(results[i]), get<1>(results[i]), get<2>(results[i]), get<3>(results[i]), get<4>(results[i]), get<5>(results[i]));
	}
}

わーい
人生


この記事が気に入ったらサポートをしてみませんか?