Advertisement
Urbani

Untitled

Jun 27th, 2016
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.30 KB | None | 0 0
  1. #include "./participant_strategy.h"
  2. #include <set>
  3.  
  4. using namespace hftbattle;
  5.  
  6. class UserStrategy : public ParticipantStrategy {
  7. public:
  8.  
  9. UserStrategy(JsonValue config) :
  10. a_(config["a"].as<int>(1)),
  11. c_(config["c"].as<int>(1)),
  12. b_(config["b"].as<int>(1)),
  13. d_(config["d"].as<int>(0)),
  14. time_not_trade(config["time_not_trade"].as<int>(10)),
  15. time_between_orders_(config["time_between_orders"].as<Microseconds>(1ms)),
  16. max_executed_amount_(config["max_executed_amount"].as<Amount>(50)),
  17. max_amount_at_price_(config["max_amount_at_price"].as<Amount>(4)),
  18. stop_loss_(config["stop_loss"].as<Decimal>(Decimal(-10000.0))),
  19. max_amount_to_run_from_best_(config["max_amount_to_run_from_best"].as<Amount>(20)),
  20. max_soft_amount_to_run_from_best_(config["max_soft_amount_to_run_from_best"].as<Amount>(64)),
  21. max_after_amount_to_run_(config["max_after_amount_to_run"].as<Amount>(42)),
  22. max_after_amount_to_run1_(config["max_after_amount_to_run1"].as<Amount>(42)) {
  23. set_stop_loss_result(stop_loss_);
  24. }
  25.  
  26. bool should_strategy_run_from_best_price(Dir dir, int a, int b, int c, int d) const {
  27. double dir_events = a * deletions_count(dir) + d * additions_count(opposite_dir(dir));
  28. // возможная оценка количества событий, которые могут сигнализировать о том, что скоро этой цены не станет
  29. double opposite_dir_events = b * deletions_count(opposite_dir(dir)) + c * additions_count(dir);
  30. // возможная оценка количества событий, которые могут сигнализировать о том, что скоро противоположной цены не станет
  31. if (dir_events - opposite_dir_events > 0) {
  32. return true;
  33. }
  34. return false;
  35. // Предлагается вместо false возвращать значение некоторого критерия, который будет говорить
  36. // о том, что есть большая вероятность исчезновения этой цены из стакана, и с нее лучше сняться.
  37. // Например, так: return (dir_events > 0.0); - если удалений + снятий больше 0, то стоит уходить с цены.
  38. // Подробности у нас в блоге http://blog.hftbattle.com.
  39. // Правильно реализовав это правило и подобрав параметры, мы получили результат
  40. // более $10000 на контрольной выборке, чего желаем и всем участникам!
  41. }
  42.  
  43. // Удаление заявки с лучшей цены с учётом её положения в очереди. Снимаем заявку только в том случае,
  44. // когда она стоит в хвосте очереди.
  45. void delete_soft_second_version(Dir dir, Price price, Amount current_amount, Amount wanted_amount,
  46. const std::vector<OrderSnapshot>& current_orders, Microseconds time_between_orders) {
  47. if (!should_strategy_run_from_best_price(dir, a_, b_, c_,d_)) {
  48. // Сюда же можно добавить отсечение по нашим сделкам: если по текущей цене недавно
  49. // была проведена сделка, то, скорее всего, выставлять заявку на эту цену будет невыгодно.
  50. // Подробное описание идеи читайте в блоге!
  51. // Скажем лишь, что реализация этой идеи позволила нам увеличить результат на $4000.
  52. // Мы уже сохранили за вас цену и время последней сделки в полях last_our_deal_price_
  53. // и last_our_deal_moment_, так что вам осталось только написать правильное условие!
  54. if(get_server_time() - last_our_deal_moment_[dir] < time_between_orders && last_our_deal_price_[dir] == price ){
  55. //if(wanted_amount > current_amount) {
  56. for (auto it = current_orders.begin(); it != current_orders.end(); ++it) {
  57. auto order = *it;
  58. if (order->status() != OrderStatus::Active) {
  59. continue;
  60. }
  61. // считаем объем, стоящий после нашей заявки
  62. const Amount amount_after_order = trading_book_info.best_volume(dir) - get_amount_before_order(order);
  63. // если с цены хорошо бы сняться и мы не сильно теряем очередь - то снимаем заявку
  64. if (amount_after_order < max_after_amount_to_run1_) {
  65. delete_order(order);
  66. }
  67. }
  68. return;
  69. //}
  70. }
  71. manage_amount_on_price(dir, price, wanted_amount, current_orders);
  72. return;
  73. }
  74. for (auto it = current_orders.begin(); it != current_orders.end(); ++it) {
  75. auto order = *it;
  76. if (order->status() != OrderStatus::Active) {
  77. continue;
  78. }
  79. // считаем объем, стоящий после нашей заявки
  80. const Amount amount_after_order = trading_book_info.best_volume(dir) - get_amount_before_order(order);
  81. // если с цены хорошо бы сняться и мы не сильно теряем очередь - то снимаем заявку
  82. if (should_strategy_run_from_best_price(dir, a_, b_, c_,d_) && amount_after_order < max_after_amount_to_run_) {
  83. delete_order(order);
  84. }
  85. }
  86. }
  87.  
  88. // В этой функции мы снимаем заявку с лучшей цены при выполнении определённых условий.
  89. // В частности, если на котировке стоят заявки с малым суммарным объёмом или наши заявки находятся в конце очереди.
  90. // В противном случае (то есть если мы считаем что стоять на лучшей сейчас выгодно) -
  91. // мы просто обрабатываем ее как обычную цену.
  92. void manage_amount_on_best_price(Dir dir, Price price, Amount wanted_amount, const std::vector<OrderSnapshot>& current_orders) {
  93. auto current_amount = std::accumulate(current_orders.cbegin(), current_orders.cend(), 0,
  94. [](Amount amount, const OrderSnapshot &order) {
  95. return amount + order->amount;
  96. });
  97. // если объем на цене совсем маленький - то снимаемся с нее
  98. if (trading_book_info.best_volume(dir) - current_amount < max_amount_to_run_from_best_) {
  99. delete_all_at_price(dir, price);
  100. return;
  101. }
  102. // если объем не превышает какого-то - то думаем, стоит ли сняться, или все же стоит держать заявки
  103. if (trading_book_info.best_volume(dir) - current_amount < max_soft_amount_to_run_from_best_) {
  104. delete_soft_second_version(dir, price, current_amount, wanted_amount, current_orders, time_between_orders_);
  105. return;
  106. }
  107. // если объем достаточно большой - то просто обрабатываем цену как все другие
  108. manage_amount_on_price(dir, price, wanted_amount, current_orders);
  109. }
  110.  
  111. // В этой функции мы поддерживаем необходимый объём заявок на ценовом уровне.
  112. void manage_amount_on_price(Dir dir, Price price, Amount wanted_amount, const std::vector<OrderSnapshot>& current_orders) {
  113. auto current_amount = std::accumulate(current_orders.cbegin(), current_orders.cend(), 0,
  114. [](Amount amount, const OrderSnapshot &order) {
  115. return amount + order->amount;
  116. });
  117. for(auto it = current_orders.rbegin(); it != current_orders.rend() && current_amount > wanted_amount; ++it) {
  118. auto order = *it;
  119. current_amount -= order->amount_rest();
  120. delete_order(order);
  121. }
  122. for(int i = 0; i < wanted_amount - current_amount; ++i) {
  123. // Мы выставляем заявки объёмом 1 лот, чтобы мы могли снимать только часть объёма,
  124. // выставленного на ценовом уровне, без потери места в очереди внутри котировки.
  125. add_limit_order(dir, price, 1);
  126. }
  127. }
  128.  
  129. void trading_book_update(const OrderBook& order_book) override {
  130. // Добавляем отсечение по времени, чтобы торговать только в определённый период дня.
  131. if (get_server_time_tm().tm_hour < time_not_trade) {
  132. return;
  133. }
  134. // Обновляем списки недавних постановок и снятий на лучшие цены
  135. update_deletions_and_additions();
  136. for (Dir dir : {BID, ASK}) {
  137. // Удаляем заявки с далёких ценовых уровней, чтобы не попадать под ограничение на набираемую позу.
  138. for(auto& order: trading_book_info.orders().orders_by_dir[dir]) {
  139. if (trading_book->get_index_by_price(dir, order->price) > 9) {
  140. delete_order(order);
  141. }
  142. }
  143. // Выставляем заявки на все видимые котировки в стакане.
  144. auto active_orders = trading_book_info.orders().get_orders_by_dir_to_map(dir);
  145. for (const auto& quote : trading_book->all_quotes(dir)) {
  146. Price quote_price = quote.get_price();
  147. Amount amount = get_wanted_amount(dir, quote_price);
  148. // По отдельности обрабатываем лучшие ценовые уровни и все остальные.
  149. if (quote_price == trading_book_info.best_price(dir)) {
  150. manage_amount_on_best_price(dir, quote_price, amount, active_orders[quote_price]);
  151. }
  152. else {
  153. manage_amount_on_price(dir, quote_price, amount, active_orders[quote_price]);
  154. }
  155. }
  156. }
  157. }
  158.  
  159. void execution_report_update(const ExecutionReport& snapshot) override {
  160. auto dir = snapshot.dir();
  161. last_our_deal_price_[dir] = snapshot.deal_price();
  162. last_our_deal_moment_[dir] = get_server_time();
  163. }
  164.  
  165. private:
  166. using Events = std::set<Microseconds>;
  167.  
  168. Decimal stop_loss_;
  169.  
  170. Amount max_executed_amount_;
  171. Amount max_amount_at_price_;
  172. Amount max_amount_to_run_from_best_;
  173. Amount max_soft_amount_to_run_from_best_;
  174. Amount max_after_amount_to_run_;
  175. Amount amount_to_add_order_;
  176. Amount max_after_amount_to_run1_;
  177.  
  178. int time_not_trade;
  179. int a_;
  180. int b_;
  181. int c_;
  182. int d_;
  183.  
  184. Microseconds time_between_orders_;
  185.  
  186. std::array<Price, 2> last_best_price_;
  187. std::array<Events, 2> deletions_by_dir_;
  188. std::array<Events, 2> additions_by_dir_;
  189. Microseconds last_reset_time_;
  190.  
  191. std::array<Price, 2> last_our_deal_price_;
  192. std::array<Microseconds, 2> last_our_deal_moment_;
  193.  
  194. // Возвращает количество снятых заявок с лучшей цены по направлению @dir за определённый промежуток времени.
  195. size_t deletions_count(const Dir dir) const {
  196. return deletions_by_dir_[dir].size();
  197. }
  198.  
  199. // Возвращает количество добавленных заявок на лучшую цену по направлению @dir за определённый промежуток времени.
  200. size_t additions_count(const Dir dir) const {
  201. return additions_by_dir_[dir].size();
  202. }
  203.  
  204. void delete_all_at_price(Dir dir, Price price) {
  205. auto orders_map = trading_book_info.orders().get_orders_by_dir_to_map(dir);
  206. auto it = orders_map.find(price);
  207. if (it == orders_map.end()) {
  208. return;
  209. }
  210. auto& active_orders = it->second;
  211. for (auto& order : active_orders) {
  212. delete_order(order);
  213. }
  214. }
  215.  
  216. // Возвращает объём, который нужно поддерживать на ценовом уровне.
  217. // В этом примере представлена очень простая версия этой функции, но зависимость объёма
  218. // от цены и направления может быть куда более сложной.
  219. Amount get_wanted_amount(Dir dir, Price price) const {
  220. Amount wanted_amount = std::min(max_executed_amount_ - dir_sign(dir) * trading_book_info.total_amount(), max_amount_at_price_);
  221. return std::max(0, wanted_amount);
  222. }
  223.  
  224. // Обновление объёмов снятых и добавленных заявок на лучших ценах.
  225. void update_deletions_and_additions() {
  226. for (Dir dir : {BID, ASK}) {
  227. const Price best_price = trading_book_info.best_price(dir);
  228. auto& deletions = deletions_by_dir_[dir];
  229. auto& additions = additions_by_dir_[dir];
  230. // Если лучшая цена изменилась, то сбросим объёмы.
  231. if (best_price != last_best_price_[dir]) {
  232. deletions.clear();
  233. additions.clear();
  234. last_best_price_[dir] = best_price;
  235. }
  236. update_events(deletions, trading_book_info.get_deleted_volume_at_price(dir, best_price));
  237. update_events(additions, trading_book_info.get_added_volume_at_price(dir, best_price));
  238. }
  239. }
  240.  
  241. void update_events(Events& events, const Amount changed_volume) const {
  242. Microseconds current_time = get_server_time();
  243. // если событие было давно - то перестаем его учитывать
  244. while (!events.empty() && current_time - *events.begin() > 17ms) {
  245. events.erase(events.begin());
  246. }
  247. if (changed_volume > 0) {
  248. events.emplace(current_time);
  249. }
  250. }
  251. };
  252. REGISTER_CONTEST_STRATEGY(UserStrategy, user_strategy)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement