From 72fb76e8c2a614dc98cda73b84ce33bcf67c3c79 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Tue, 13 Mar 2018 23:25:41 +0100 Subject: [PATCH] WTF --- .gitignore | 3 + common.cpp | 0 common.h | 4 + decider.h | 13 +++- macd.cpp | 39 ++++++++++ main.cpp | 57 -------------- matrix.h | 24 ++++++ network.h | 40 ++++++++++ tester.cpp | 65 ++++++++++++++++ trainer.h | 215 ++++++++++++++++++++++++++--------------------------- wtf.cpp | 58 +++++++++++---- 11 files changed, 333 insertions(+), 185 deletions(-) create mode 100644 common.cpp create mode 100644 common.h create mode 100644 macd.cpp delete mode 100644 main.cpp create mode 100644 tester.cpp diff --git a/.gitignore b/.gitignore index eb1a7ef..199093c 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ *.ilg *.ind *.ist + +/net/ +*.net diff --git a/common.cpp b/common.cpp new file mode 100644 index 0000000..e69de29 diff --git a/common.h b/common.h new file mode 100644 index 0000000..a01be47 --- /dev/null +++ b/common.h @@ -0,0 +1,4 @@ +#include "network.h" +#include "decider.h" + +using current_decider = neural_decider<24, 16, 16, 32, 16>; diff --git a/decider.h b/decider.h index a43258c..f0528fb 100644 --- a/decider.h +++ b/decider.h @@ -42,9 +42,6 @@ public: network_t network; - double start_money; - unsigned start_stock; - neural_decider() : network(), macd_decider() { } neural_decider(typename network_t::normalizer_t normalizer) : network(normalizer), macd_decider() { } @@ -64,6 +61,16 @@ public: return abs(buy - sell) <= .5 ? 0 : amount * start_stock / 10; } + std::ostream& save(std::ostream& stream) { + network.save(stream); + + return stream; + } + + void load(std::istream& stream) { + network.load(stream); + } + virtual void reset() override { macd_decider::reset(); diff --git a/macd.cpp b/macd.cpp new file mode 100644 index 0000000..69e62f8 --- /dev/null +++ b/macd.cpp @@ -0,0 +1,39 @@ +#include +#include + +#include "helpers.h" +#include "argh.h" + +int main(int argc, const char* argv[]) +{ + argh::parser args; + args.add_params({ "l", "low" }); + args.add_params({ "h", "high" }); + args.add_params({ "s", "signal" }); + + args.parse(argc, argv); + + unsigned low, high, s; + + args({"l", "low"}, 12) >> low; + args({"h", "high"}, 26) >> high; + args({"s", "signal"}, 9) >> s; + + unsigned max = std::max({ low, high, s }); + buffer prices(max); + buffer macd(max); + buffer signal(max); + + + double price; + std::cout << "no,price,macd,signal,delta" << std::endl; + for (int i = 0; std::cin >> price; i++) { + prices.add(price); + double value = ema(prices.begin(), prices.begin() + low) - ema(prices.begin(), prices.begin() + high); + macd.add(value); + signal.add(ema(macd.begin(), macd.begin() + s)); + + std::cout << i << "," << prices[0] << "," << macd[0] << "," << signal[0] << "," << prices[1] - prices[0] << std::endl; + } +} + diff --git a/main.cpp b/main.cpp deleted file mode 100644 index bd1d45d..0000000 --- a/main.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include -#include -#include -#include - -double expavg(const std::vector &values, int start, int n) -{ - double a = 1 - 2./(n + 1); - - double nominator = 0., denominator = 0.; - double b = 1.; - - for (int i = 0; i < n; i++) { - nominator += b*values[start - i]; - denominator += b; - - b *= a; - } - - return nominator / denominator; -} - -int main(int argc, char **argv) -{ - int low = 12, high = 26, s = 9; - - if (argc >= 2) - low = std::atoi(argv[2]); - - if (argc >= 3) - high = std::atoi(argv[4]); - - if (argc >= 4) - s = std::atoi(argv[3]); - - std::vector prices; - double price; - - while (std::cin >> price) { - prices.push_back(price); - } - - std::vector macd(prices.size()); - std::vector signal(prices.size()); - - for (int i = 0; i < prices.size(); ++i) { - macd[i] = expavg(prices, i, std::min(i, low)) - expavg(prices, i, std::min(i, high)); - signal[i] = expavg(macd, i, std::min(i, s)); - } - - std::cout << "price,macd,signal,delta" << std::endl; - for (int i = 1; i < prices.size(); ++i) { - std::cout << prices[i] << "," << macd[i] << "," << signal[i] << "," << prices[i] - prices[i-1] << std::endl; - } -} diff --git a/matrix.h b/matrix.h index f1dd306..2afbeab 100644 --- a/matrix.h +++ b/matrix.h @@ -159,6 +159,30 @@ class matrix return stream; } + + std::ostream& save(std::ostream& stream) + { + T temp; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; j++) { + temp = get(i, j); + stream.write(reinterpret_cast(&temp), sizeof(T)); + } + } + + return stream; + } + + void load(std::istream& stream) + { + T temp; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; j++) { + stream.read(reinterpret_cast(&temp), sizeof(T)); + set(i, j, temp); + } + } + } }; template matrix operator*(const T& lhs, const matrix& rhs) { diff --git a/network.h b/network.h index 41e629f..e59c4c0 100644 --- a/network.h +++ b/network.h @@ -3,6 +3,7 @@ #include "matrix.h" #include +#include template struct layer { @@ -43,6 +44,19 @@ struct layer { { return combine(rhs, combiner, combiner); } + + std::ostream& save(std::ostream& stream) { + weights.save(stream); + bias.save(stream); + + return stream; + } + + void load(std::istream& stream) + { + weights.load(stream); + bias.load(stream); + } }; template struct layer_types; @@ -111,6 +125,18 @@ public: { return combine(rhs, combiner, combiner); } + + std::ostream& save(std::ostream& stream) + { + current.save(stream); + + return stream; + } + + void load(std::istream& stream) + { + current.load(stream); + } }; template @@ -171,6 +197,20 @@ public: { return combine(rhs, combiner, combiner); } + + std::ostream& save(std::ostream& stream) + { + base::save(stream); + subnetwork.save(stream); + + return stream; + } + + void load(std::istream& stream) + { + base::load(stream); + subnetwork.load(stream); + } }; #endif diff --git a/tester.cpp b/tester.cpp new file mode 100644 index 0000000..76ab05b --- /dev/null +++ b/tester.cpp @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "helpers.h" +#include "argh.h" +#include "common.h" + +int main(int argc, const char* argv[]) +{ + argh::parser args; + args.add_params({ "s", "stock" }); + args.add_params({ "m", "money" }); + + args.parse(argc, argv); + + std::string network, input; + + args(1) >> network; + args(2) >> input; + + double money; + unsigned stock; + + args({"s", "stock"}, 1000) >> stock; + args({"m", "money"}, 1000.) >> money; + + std::function normalizer = [](const double& result) -> double { return erf(result); }; + current_decider decider(normalizer); + + std::ifstream network_file(network, std::ios::in | std::ios::binary); + std::ifstream input_file(input); + + decider.load(network_file); + + double price; + decider.start_money = money; + decider.start_stock = stock; + std::cout << "x,price,decsion,money,stock" << std::endl; + for (int i = 0; input_file >> price; i++) { + auto decision = decider.decide(price, money, stock); + auto current = price * stock + money; + auto max_credit = std::max(current * 0.05, -1e4); + + if (decision < 0) { + decision = std::max(decision, -stock); // cannot sell more than we actually have + } else if (decision > 0) { + decision = std::min(floor((money + max_credit) / price), decision); + } + + money -= price * decision; + stock += decision; + + /* std::cout */ + /* << i << "," */ + /* << price << "," */ + /* << decision << "," */ + /* << money << "," */ + /* << stock */ + /* << std::endl; */ + } + std::cout << "Koniec: " << money + stock*price; + /* decider.network.save(std::cout); */ +} + diff --git a/trainer.h b/trainer.h index bec8d8e..e3753b1 100644 --- a/trainer.h +++ b/trainer.h @@ -5,22 +5,15 @@ #include #include #include +#include template struct trained { - unsigned int id; - T decider; - - double monies; - unsigned stock; - double wealth; - - void recalculate(double price) - { - wealth = monies + stock*price; - } + unsigned id; + unsigned position; double score; + T decider; }; template @@ -34,14 +27,20 @@ class trainer { std::size_t n; public: + using dataset = std::vector; + double money; unsigned stock; + unsigned int generation; - std::function> x)> q; + std::function>, const dataset&, double, unsigned)> q; trainer(double money, unsigned stock, std::size_t n, std::function factory) - : factory(factory), id(0), money(money), stock(stock), n(n), - q([](std::shared_ptr> x){ return x->wealth; }), random_engine(std::time(0)) + : factory(factory), id(0), generation(1), money(money), stock(stock), n(n), + q([](std::shared_ptr> x, const dataset& input, double money, unsigned stock) { + return money + input.back() * stock; + }), + random_engine(std::time(0)) { add(n); } @@ -67,105 +66,109 @@ public: trainees.push_back(trainee); } - int train(std::shared_ptr> trainee, double price) + void evolve() { - auto decision = trainee->decider.decide(price, trainee->monies, trainee->stock); - auto current = price*trainee->stock + trainee->monies; - auto max_credit = std::max(current * 0.05, -1e4); - - /* std::cout << "D: " << decision << " C: " << current << " P: " << price << " MC: " << max_credit << std::endl; */ - if (decision > 0 && trainee->monies - decision*price < -max_credit) { - decision = floor((trainee->monies + max_credit) / price); - } - - if (decision < 0 && -decision > trainee->stock) { - decision = -trainee->stock; - } - - trainee->stock += decision; - trainee->monies -= price*decision; - trainee->recalculate(price); - - return decision; - } - - void test(std::istream& input) - { - for (auto trainee : trainees) { - trainee->monies = money; - trainee->stock = stock; - - trainee->decider.start_money = money; - trainee->decider.start_stock = stock; - trainee->decider.reset(); - } - - double price, start; - input >> price; - start = price*stock + money; - - do { - for (auto trainee : trainees) { - train(trainee, price); - } - } while (input >> price); - - auto hodl = price * stock + money; - std::cout << "Zakonczono testy " << trainees.size() << " przypadkow." << std::endl; - std::cout << "HODL: " << hodl << " START: " << start << std::endl; - std::cout << "-----------------------" << std::endl; - - normalize(); - - for (auto trainee : trainees) { - std::cout - << "#" << trainee->id << ": " << trainee->wealth - << " [" << trainee->wealth - hodl << "] (" << trainee->score << ") " - << trainee->stock << " akcji, " - << trainee->monies << " gelda w banku. " << std::endl; - } - + sort(); filter(); breed(); + + // cleanup before next training sessions + for (auto t : trainees) { + t->score = 0; + } } - void normalize() + void train(const dataset& input, std::shared_ptr> trainee) + { + trainee->decider.start_money = money; + trainee->decider.start_stock = stock; + trainee->decider.reset(); + + double money = this->money; + unsigned stock = this->stock; + + for (double price : input) { + auto decision = trainee->decider.decide(price, money, stock); + auto current = price * stock + money; + auto max_credit = std::max(current * 0.05, -1e4); + + if (decision < 0) { + decision = std::max(decision, -stock); // cannot sell more than we actually have + } else if (decision > 0) { + decision = std::min(floor((money + max_credit) / price), decision); + } + + money -= price * decision; + stock += decision; + } + + trainee->score += q(trainee, input, money, stock); + + auto last = input.back(); + auto first = input.front(); + auto wealth = money + stock * last; + + auto hodl = this->money + this->stock * last; + auto start = this->money + this->stock * first; + + std::cout + << "#" << trainee->id << ": " << wealth + + << std::showpos + << " H: " << wealth - hodl << " (" << (wealth - hodl) / hodl * 100 << "%)" + << " S: " << wealth - start << " (" << (wealth - start) / start * 100 << "%) " + << std::noshowpos + + << stock << " akcji, " + << money << " gelda w banku. " + << std::endl; + } + + void train(const dataset& input, const std::string& name) + { + std::cout << "Zestaw " << name + << " GEN #" << this->generation + << " start: " << money + input.front() * stock + << " HODL: " << money + input.back() * stock + << std::endl; + + for (auto trainee : trainees) { + train(input, trainee); + } + } + + void sort() { std::sort(trainees.begin(), trainees.end(), [=](std::shared_ptr> a, std::shared_ptr> b){ - return q(a) > q(b); + return a->score > b->score; }); - auto high = q(*trainees.begin()); - auto low = q(*(trainees.end() - 1)); - - // best = 1, worst = 0 + unsigned i = 0; for (auto t : trainees) { - t->score = (q(t) - low) / (high - low); - }; + t->position = i++; + } } void filter() { - /* static std::exponential_distribution distribution(0.50); */ + static std::uniform_real_distribution distribution(0.0, 1.0); + auto random = [=](){ return distribution(random_engine); }; + + auto iterator = std::remove_if(trainees.begin(), trainees.end(), [&](std::shared_ptr> t) { + return random() < (double)t->position / n; + }); - /* auto random = [=](){ return 1. - std::clamp(0., distribution(random_engine), 2.)/2.1; }; */ - /* auto iterator = std::remove_if(trainees.begin(), trainees.end(), [=](std::shared_ptr> t) { */ - /* return random() > t->score; */ - /* }); */ - - trainees.erase(trainees.begin() + 49, trainees.end()); + trainees.erase(iterator, std::end(trainees)); std::cout << "Przy życiu pozostają: "; for (auto trainee : trainees) { - std::cout << "#" << trainee->id << " "; + std::cout << "#" << trainee->id << " (" << trainee->position << ") "; } - std::cout << std::endl; } void breed() { std::size_t diff = n - trainees.size(); - std::cout << "---------------------------------------" << std::endl; std::cout << "W populacji brakuje " << diff << " sieci, aktualnie " << trainees.size() << "." << std::endl; std::vector probability; @@ -173,44 +176,38 @@ public: probability.push_back(t->score); } - std::discrete_distribution distribution(probability.begin(), probability.end()); - std::exponential_distribution exponential(1.5); - + std::discrete_distribution distribution(probability.begin(), probability.end()); + std::exponential_distribution exponential(1.5); + std::uniform_real_distribution ratio(0.0, 1.0); + auto combiner = [=](const double& a, const double& b){ auto mutation = (rand() % 2 ? -1 : 1) * exponential(random_engine); if (exponential(random_engine) < 1) { - return .6 * a + .4 * b + mutation; + auto r = ratio(random_engine); + return r * a + (1 - r) * b + mutation; } return (rand() % 2 ? a : b) + mutation; }; unsigned first, second; - for (int i = 0; i < diff; i++) { + for (int i = 0; i < diff - 4; i++) { first = distribution(random_engine); do { second = distribution(random_engine); } while (first == second); auto combined = trainees[first]->decider.combine(trainees[second]->decider, combiner); std::cout << "Łączenie #" << trainees[first]->id << " z #" << trainees[second]->id << " dało #" << (id+1) << std::endl; + add(combined); } + + add(4); // some random things + + generation++; } - void see_best(std::istream& stream) - { - std::shared_ptr> trainee = this->trainees[0]; - - std::cout << "price,decision" << std::endl; - double price; - - trainee->monies = money; - trainee->stock = stock; - - trainee->decider.reset(); - while (stream >> price) { - int decision = train(trainee, price); - std::cout << price << "," << decision << std::endl; - } + std::vector>> population() { + return trainees; } }; diff --git a/wtf.cpp b/wtf.cpp index 6651451..b0a9622 100644 --- a/wtf.cpp +++ b/wtf.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "argh.h" #include "matrix.h" @@ -14,7 +15,7 @@ #include "decider.h" #include "trainer.h" -using current_decider = neural_decider<24, 12, 12, 32, 16>; +using current_decider = neural_decider<24, 16, 16, 32, 16>; int main(int argc, char* argv[]) { @@ -23,27 +24,24 @@ int main(int argc, char* argv[]) args.add_params({"-s", "--stock"}); args.add_params({"-p", "--population"}); args.add_params({"-n", "--iterations"}); + args.add_params({"-o", "--output-dir"}); args.parse(argc, argv); double money; unsigned stock, population, iterations; - std::string input_file; + std::string input_file, output_dir; args({ "m", "money" }, 1000.) >> money; args({ "s", "stock" }, 1000) >> stock; args({ "p", "population" }, 25) >> population; args({ "n", "iterations" }, 4) >> iterations; - args(1) >> input_file; + args({ "o", "output-dir" }, "") >> output_dir; std::uniform_real_distribution distribution(-2.0, 2.0); std::uniform_real_distribution bias_distribution(-16.0, 16.0); std::random_device rd; - - // - // Engines - // std::mt19937 random_engine(rd()); std::function randomizer = [&](const int&, const int&) -> double { @@ -64,19 +62,47 @@ int main(int argc, char* argv[]) }; trainer train(money, stock, population, factory); - std::fstream input; - input.open(input_file); + std::map::dataset> datasets; + for (auto it = args.begin() + 1; it != args.end(); it++) { + std::string filename = *it; + std::ifstream file; + file.open(filename); + if (!file.is_open()) continue; - for (int i = 0; i < iterations; i++) { - input.clear(); - input.seekg(0); + trainer::dataset set; + double price; + while (file >> price) set.push_back(price); - train.test(input); + datasets[filename] = set; + + file.close(); + std::cout << "Zaladowano zestaw testowy " << filename << " z " << set.size() << " wartosciami." << std::endl; } - input.clear(); - input.seekg(0); + if (datasets.size() == 0) { + std::cout << "Brak poprawnie zaladowanych zestawow testowych." << std::endl; + return -1; + } - train.see_best(input); + while (train.generation <= iterations) { + for (auto pair : datasets) { + train.train(pair.second, pair.first); + } + train.evolve(); + } + + if (!output_dir.empty()) { + for (auto trained : train.population()) { + std::stringstream stream; + stream << output_dir << trained->id << ".net"; + std::string filename = stream.str(); + + std::cout << "Zapisuje siec #" << trained->id << " do pliku " << filename << std::endl; + + std::ofstream file(filename, std::ios::out | std::ios::binary); + trained->decider.save(file); + file.close(); + } + } }