limit.jl
1 using .Instances 2 import .Instances: committed, PositionOpen, PositionClose, freecash 3 using .OrderTypes: 4 LimitOrderType, PositionSide, ExchangeID, ShortSellOrder, FOKOrderType, IOCOrderType 5 using Strategies: NoMarginStrategy 6 using Base: negate 7 using .Misc: Long, Short 8 using .Lang: @ifdebug 9 import Base: fill! 10 11 @doc "Union type representing limit order increase operations. Includes Buy and Sell Short orders." 12 const IncreaseLimitOrder{A,E} = Union{LimitOrder{Buy,A,E},ShortLimitOrder{Sell,A,E}} 13 14 @doc "Union type representing limit order reduction operations. Includes Sell and Buy Short orders." 15 const ReduceLimitOrder{A,E} = Union{LimitOrder{Sell,A,E},ShortLimitOrder{Buy,A,E}} 16 17 @doc "Type representing a limit trade, includes long position limit orders." 18 const LimitTrade{S,A,E} = Trade{<:LimitOrderType{S},A,E,Long} 19 20 @doc "Type representing a short limit trade, includes short position limit orders." 21 const ShortLimitTrade{S,A,E} = Trade{<:LimitOrderType{S},A,E,Short} 22 23 @doc "Type representing a limit buy trade, specific to long position buy limit orders." 24 const LimitBuyTrade{A,E} = LimitTrade{Buy,A,E} 25 26 @doc "Type representing a limit sell trade, specific to long position sell limit orders." 27 const LimitSellTrade{A,E} = LimitTrade{Sell,A,E} 28 29 @doc "Type representing a short limit buy trade, specific to short position buy limit orders." 30 const ShortLimitBuyTrade{A,E} = ShortLimitTrade{Buy,A,E} 31 32 @doc "Type representing a short limit sell trade, specific to short position sell limit orders." 33 const ShortLimitSellTrade{A,E} = ShortLimitTrade{Sell,A,E} 34 35 @doc "Union type representing limit trade increase operations. Includes Buy and Sell Short trades." 36 const IncreaseLimitTrade{A,E} = Union{LimitBuyTrade{A,E},ShortLimitSellTrade{A,E}} 37 38 @doc "Union type representing limit trade reduction operations. Includes Sell and Buy Short trades." 39 const ReduceLimitTrade{A,E} = Union{LimitSellTrade{A,E},ShortLimitBuyTrade{A,E}} 40 41 @doc """ Places a limit order in the strategy 42 43 $(TYPEDSIGNATURES) 44 45 This function places a limit order with specified parameters in the strategy `s`. The `type` argument specifies the type of the order. The `price` defaults to the current price at the given `date` if not provided. The `take` and `stop` arguments are optional and default to `nothing`. If `skipcommit` is true, the function will not commit the order. Additional arguments can be passed via `kwargs`. 46 47 """ 48 function limitorder( 49 s::Strategy, 50 ai, 51 amount; 52 date, 53 type, 54 price=priceat(s, type, ai, date), 55 take=nothing, 56 stop=nothing, 57 skipcommit=false, 58 kwargs..., 59 ) 60 @price! ai price take stop 61 @amount! ai amount 62 comm = Ref(committment(type, ai, price, amount)) 63 @debug "create limitorder:" ai = raw(ai) price amount comm[] is_comm = iscommittable( 64 s, type, comm, ai 65 ) free = freecash(ai, posside(ai)) 66 if skipcommit || iscommittable(s, type, comm, ai) 67 basicorder(ai, price, amount, comm, SanitizeOff(); date, type, kwargs...) 68 end 69 end 70 71 _cashfrom(s, _, o::IncreaseOrder) = st.freecash(s) + committed(o) 72 _cashfrom(_, ai, o::ReduceOrder) = st.freecash(ai, positionside(o)()) + committed(o) 73 74 @doc """ Checks if the provided trade is the last fill for the given asset instance. 75 76 $(TYPEDSIGNATURES) 77 """ 78 function islastfill(ai::AssetInstance, t::Trade{<:LimitOrderType}) 79 o = t.order 80 t.amount != o.amount && isfilled(ai, o) 81 end 82 @doc """ Checks if the provided trade is the first fill for the given asset instance. 83 84 $(TYPEDSIGNATURES) 85 """ 86 function isfirstfill(::AssetInstance, t::Trade{<:LimitOrderType}) 87 o = t.order 88 attr(o, :unfilled)[] == negate(t.amount) 89 end 90 91 @doc """ Adds a limit order to the pending orders of the strategy. 92 93 $(TYPEDSIGNATURES) 94 95 This function takes a strategy, a limit order of type LimitOrderType{S}, and an asset instance as arguments. It adds the limit order to the pending orders of the strategy. If `skipcommit` is set to false (default), the order is committed and held. Returns true if the order was successfully added, otherwise false. 96 """ 97 function queue!( 98 s::Strategy, o::Order{<:LimitOrderType{S}}, ai; skipcommit=false 99 ) where {S<:OrderSide} 100 @debug "queue limitorder:" is_comm = iscommittable(s, o, ai) 101 # This is already done in general by the function that creates the order 102 skipcommit || iscommittable(s, o, ai) || return false 103 push!(s, ai, o) 104 @deassert hasorders(s, ai, positionside(o)) 105 skipcommit || commit!(s, o, ai) 106 hold!(s, ai, o) 107 return true 108 end