trades.jl
1 @doc """Performs cleanups after a trade (attempt). 2 3 $(TYPEDSIGNATURES) 4 5 """ 6 aftertrade!(s, ai, o, t=nothing) = nothing 7 8 with_slippage(args...; kwargs...) = nothing 9 10 maketrade(args...; kwargs...) = nothing 11 12 @doc """ Unconditionally dequeues immediate orders. 13 14 $(TYPEDSIGNATURES) 15 16 This function is called after a trade to remove filled 'Fill Or Kill' (FOK) or 'Immediate Or Cancel' (IOC) orders from the strategy's order queue. 17 """ 18 function aftertrade!(s::Strategy, ai, o::Union{AnyFOKOrder,AnyIOCOrder,AnyMarketOrder}, t=nothing) 19 if t isa Trade 20 position!(s, ai, t) 21 end 22 decommit!(s, o, ai, true) 23 delete!(s, ai, o) 24 isfilled(ai, o) || st.call!(s, o, NotEnoughCash(_cashfrom(s, ai, o)), ai) 25 end 26 27 @doc """ Removes a filled limit order from the queue 28 29 $(TYPEDSIGNATURES) 30 31 The function is used post-trade to clean up the strategy's order queue. 32 """ 33 aftertrade!(s::Strategy, ai, o::Order, t=nothing) = begin 34 if t isa Trade 35 position!(s, ai, t) 36 end 37 if isfilled(ai, o) 38 decommit!(s, o, ai) 39 delete!(s, ai, o) 40 end 41 end 42 43 44 @doc """ Executes a trade with the given parameters and updates the strategy state. 45 46 $(TYPEDSIGNATURES) 47 48 This function executes a trade based on the given order and asset instance. It calculates the actual price, creates a trade using the `maketrade` function, and updates the strategy and asset instance. If the trade cannot be executed (e.g., not enough cash), the function updates the state as if the order was filled without creating a trade. The function returns the created trade or nothing if the trade could not be executed. 49 50 """ 51 function trade!( 52 s::Strategy, 53 o, 54 ai; 55 date, 56 price, 57 actual_amount, 58 fees=maxfees(ai), 59 slippage=true, 60 kwargs..., 61 ) 62 @deassert abs(committed(o)) > 0.0 63 @ifdebug s.debug_afterorder() 64 if !isnothing(actual_amount) 65 if o isa ReduceOnlyOrder 66 actual_amount = min(actual_amount, ai.limits.amount.max) 67 else 68 @amount! ai actual_amount 69 end 70 end 71 actual_price = slippage ? with_slippage(s, o, ai; date, price, actual_amount) : price 72 @price! ai actual_price 73 trade = maketrade(s, o, ai; date, actual_price, actual_amount, fees, kwargs...) 74 isnothing(trade) && begin 75 # unqueue or decommit order if filled 76 aftertrade!(s, ai, o) 77 return nothing 78 end 79 _update_from_trade!(s, ai, o, trade; actual_price) 80 end 81 82 function _update_from_trade!(s::Strategy, ai, o, trade; actual_price) 83 @ifdebug s.debug_beforetrade(s, ai, o, trade, actual_price) 84 # record trade 85 @deassert !isdust(ai, o) committed(o), o 86 # Fills the order 87 fill!(s, ai, o, trade) 88 push!(trades(ai), trade) 89 push!(trades(o), trade) 90 # update asset cash and strategy cash 91 cash!(s, ai, trade) 92 # unqueue or decommit order if filled 93 # and update position state 94 aftertrade!(s, ai, o, trade) 95 call!(s, ai, trade, NewTrade()) 96 @ifdebug s.debug_aftertrade(s, ai, o) 97 @ifdebug s.debug_check_committments(s, ai) 98 @ifdebug s.debug_check_committments(s, ai, trade) 99 return trade 100 end