k100
k100 личный блог
09 октября 2017, 15:14

Торговая система своими руками. Часть 8. Формирование закрытых позиций и подсчёт статистики.

     Добрый день. В предыдущих частях я описывал, как на C# сделал собственный тестер, применяя объектно-ориентированный подход, рассказывал про интерфейсы, про их реализации, и, рассказывал про работу с БД. На данный момент осталось совсем немного. В этом топике я опишу вариант расчёта результатов работы стратегии.

     Чтобы не запутаться, даже не читая предыдущие топики, поясню, что есть и к чему надо придти. Есть стратегии – это некий объект программы, который выставляет заявки на основе получаемой маркет-даты. Заявки (Order) регистрируются системой. Также, регистрируются сделки прошедшие по заявке (каждая заявка имеет список сделок — List<Trades> trades). После прогона стратегии, все заявки и сделки сохраняются в БД, и после, их можно извлечь и посчитать по ним статистику работы стратегии. По сути, эта статистика состоит из двух аспектов: сами закрытые позиции и оценка эффективности на их основе. Начнём с первого. Вот интерфейс, который принимает заявки со сделками, и, выдаёт, собственно, список закрытых позиций:

interface IClosePositionManager
{
   List<ClosePosition> ClosePositions (List<Order> orders);
}

     Класс ClosePosition, имеет следующие поля: id закрытой позиции, объём, сделка инициатор, закрывающая сделка, нарастающий итог, профит/убыток, комиссия, время в позиции и т.д.

     Как реализовать этот интерфейс? Сделки проходят по разным ценам, и чтобы пазл сложился нужно последовательно выполнить расчёт – по сути, надо свести разнонаправленные сделки по своим ценам. Для расчёта использую очереди и рекурсию. Беру все сделки по символу и ранжирую их по порядку (по Id сделки). Далее, начинаю считать. Беру первую сделку (объём, цена) и помещаю её в очередь, беру следующую, если направление то же, то и её помещаю в очередь. Если направление противоположное, то формируется закрытая позиция. Тут важен объём. В простом случае, объёмы текущей сделки и сделки из очереди равны – они схлопнулись и текущая сделка и сделка из очереди ушли, все по своим ценам. Если объём текущей меньше чем из очереди, то текущая уходит, а объём из очереди кратно уменьшается. А если объём текущей больше чем общём из очереди – то текущая, как бы проваливается ниже, кратно поглощая сделки из очереди. Код, если кому надо – приведу. Соответственно по каждой закрытой позиции есть цена покупки и продажи, на основе которых считается профит/убыток.

     Теперь вторая составляющая статистики – оценка эффективности работы стратегии на основе её закрытых позиций:

interface IResultManager
{
   IndexOfEffectiveness Calc(List<ClosePosition> closePositions);
}

     Класс IndexOfEffectiveness включает в себя набор стандартных (да и вообще, каких угодно) показателей: общая доходность, DrawDown, PF, RF, средняя сделка, Шарп и т.д.:

class IndexOfEffectiveness
{
   [DisplayName("Общая доходность")]
   public BuySellResult<double> Yield { get; set; }

   [DisplayName("Максимальный DrawDown")]
   public BuySellResult<double> MDD { get; set; }

   [DisplayName("Profit Factor")]
   public BuySellResult<double> PF { get; set; }

   [DisplayName("Recovery Factor")]
   public BuySellResult<double> RF { get; set; }

   … и т.д.
}

     Тут перечислены все необходимые статистические показатели. Важно отметить, что в качестве возвращаемого типа каждого показателя используется обобщённый класс-обёртка BuySellResult, состоящий из трёх полей – покупки, продажи, всё вместе. Это нужно чтобы разделить, например, Максимальный DrawDown по покупкам и продажам.

     Что касается самой реализации интерфейса IResultManager (метод Calc), то тут, нудно и последовательно, выполняется расчет всех показателей:

public IndexOfEffectiveness Calc(List<ClosePosition> closePositions)
{
   var buyPositions = closePositions
       .Where(cp => cp.Init.Order
           .Action == OrderAction.Buy);

   var sellPositions = closePositions
      .Where(cp => cp.Init.Order
            .Action == OrderAction.Sell);

   var tradesCount = new BuySellResult<int>()
   {
     Buy = buyPositions.Count(),
     Sell = sellPositions.Count(),
     All = closePositions.Count()
   };

   var winPositions = new BuySellResult<IEnumerable<ClosePosition>>()
   {
     Buy = buyPositions.Where(cp => 
        Math.Sign(cp.ClearProfit) == 1),
     Sell = sellPositions.Where(cp => 
        Math.Sign(cp.ClearProfit) == 1),
     All = closePositions.Where(cp => 
        Math.Sign(cp.ClearProfit) == 1)
   };

   var winCount = new BuySellResult<int>()
   {
     Buy = winPositions.Buy.Any() ? winPositions.Buy.Count() : 0,
     Sell = winPositions.Sell.Any() ? winPositions.Sell.Count() : 0,
     All = winPositions.All.Any() ? winPositions.All.Count() : 0
   };
   ... и т.д.
}

     И всё остальное в том же духе. В конце создаётся класс IndexOfEffectiveness и ему передаются все рассчитанные выше показатели.

     Кстати в классе IndexOfEffectiveness используются атрибуты (в частности DisplayName из стандартного пространства имён System.ComponentModel). Атрибуты (или аннотации в Java) делают программирование более декларативным, по сути, это простейший вид рефлексии. Например, в DisplayName я указываю, как должна называться соответствующая колонка в таблице отображающий результаты. При инициализации таблиц в visual studio, этот атрибут подхватывается. Также, например, атрибуты используют для задания ограничений, которые автоматически проверяются в определённый момент. Можно реализовать собственные атрибуты с оригинальным поведением.

     После прогона стратегии, рассчитываются закрытые позиции и показатели эффективности. Эти данные передаются в форму для визуализации результата. Про саму визуализацию я напишу в следующем посте.

4 Комментария
  • Boris Litvinov
    09 октября 2017, 20:04
    какой коннектор используете?
      • Boris Litvinov
        09 октября 2017, 20:46
        k100, сейчас на транзак пытаюсь уйти, транзак не пробывали?
        Вообще как вамскорость на смарт ком?
        Изучаю C#. Уже многое понятно и по сути написать простого бота знаний хватит, а вот терминал, работу с БД и тестер пока нет!

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн