/ Executors / src / trades.jl
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