/ Executors / src / orders / iter.jl
iter.jl
  1  using .Strategies: PriceTime, asset_bysym
  2  import .Instances: trades
  3  
  4  @doc """
  5  A data structure for maintaining a collection of iterators.
  6  
  7  $(FIELDS)
  8  """
  9  struct OrderIterator
 10      iters::Vector{Iterators.Stateful}  # Vector of `Iterators.Stateful`
 11      OrderIterator(args...) = new([Iterators.Stateful(a) for a in args])
 12      OrderIterator(gen) = new([Iterators.Stateful(a) for a in gen])
 13  end
 14  
 15  @doc """
 16  Finds and returns the iterator with the smallest value.
 17  
 18  $(TYPEDSIGNATURES)
 19  """
 20  _findmin(non_empty_iters) = begin
 21      iters = non_empty_iters
 22      min_val, iter_idx = findmin(peek, iters)
 23      min_val, iters[iter_idx]
 24  end
 25  
 26  @doc """
 27  Filters out empty iterators and returns the smallest value.
 28  
 29  $(TYPEDSIGNATURES)
 30  """
 31  _do_orders_iter(oi) = begin
 32      # Filter out empty iterators
 33      non_empty_iters = filter!(!isempty, oi.iters)
 34  
 35      # Check if all iterators are empty
 36      len = length(non_empty_iters)
 37      if len == 0
 38          nothing
 39      elseif len == 1
 40          popfirst!(non_empty_iters[1]), nothing
 41      else
 42          _, min_iter = _findmin(non_empty_iters)
 43  
 44          # Remove the smallest value from the iterator and return it
 45          popfirst!(min_iter), nothing
 46      end
 47  end
 48  
 49  @doc """
 50  Returns the next element in the OrderIterator.
 51  
 52  $(TYPEDSIGNATURES)
 53  """
 54  Base.iterate(oi::OrderIterator, _) = _do_orders_iter(oi)
 55  Base.iterate(oi::OrderIterator) = _do_orders_iter(oi)
 56  
 57  @doc """
 58  Checks if the OrderIterator is empty.
 59  
 60  $(TYPEDSIGNATURES)
 61  """
 62  Base.isdone(oi::OrderIterator) = isempty(oi.iters) || all(isempty, oi.iters)
 63  
 64  @doc """
 65  Returns the element type of the OrderIterator.
 66  
 67  $(TYPEDSIGNATURES)
 68  """
 69  Base.eltype(::OrderIterator) = Pair{PriceTime,<:Order}
 70  
 71  @doc """
 72  Collects all elements of the OrderIterator into a Vector.
 73  
 74  $(TYPEDSIGNATURES)
 75  """
 76  function Base.collect(oi::OrderIterator)
 77      out = Vector{eltype(oi)}()
 78      push!(out, (v for v in oi)...)
 79  end
 80  
 81  function Base.collect(goi::Base.Generator{OrderIterator})
 82      out = Vector{promote_type((eltype(oi) for oi in goi)...)}()
 83      for oi in goi
 84          push!(out, oi...)
 85      end
 86      out
 87  end
 88  
 89  @doc """
 90  Returns the last element in the OrderIterator.
 91  
 92  $(TYPEDSIGNATURES)
 93  """
 94  Base.last(oi::OrderIterator) =
 95      let out = first(oi)
 96          for v in oi
 97              out = v
 98          end
 99          out
100      end
101  
102  @doc """
103  Counts the number of elements in the OrderIterator.
104  
105  $(TYPEDSIGNATURES)
106  """
107  Base.count(oi::OrderIterator) = count((_) -> true, oi)
108  
109  trades(s::Strategy) = Iterators.flatten(trades(ai) for ai in s.universe)
110  function tradescount(s::Strategy)
111      sum((length(trades(ai)) for ai in s.universe); init=0) +
112      sum((length(trades(o)) for o in values(s)); init=0)
113  end
114  
115  function closedorders(s::Strategy)
116      Misc.UniqueIterator(
117          (
118              t.order for
119              t in trades(s) if !isopen(asset_bysym(s, raw(t.order.asset)), t.order)
120          );
121          by=o -> o.id,
122      )
123  end