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