/ OrderTypes / src / trades.jl
trades.jl
  1  using .Lang: @deassert
  2  using Base: negate
  3  using .Misc: DFT
  4  
  5  @doc "The quantity of the base currency being exchanged."
  6  signedamount(amount, ::AnyBuyOrder) = amount
  7  signedamount(amount, ::AnySellOrder) = negate(amount)
  8  @doc "The quantity of the quote currency being exchanged."
  9  signedsize(size, ::IncreaseOrder) = negate(size)
 10  signedsize(size, ::ReduceOrder) = size
 11  
 12  # TODO: abstract `Trade` and implement simple trades and richer trades for margin trading
 13  @doc """An order, successfully executed from a strategy request.
 14  
 15  $(FIELDS)
 16  
 17  Entry trades: The date when the order was actually opened, during backtesting, it is usually `date + tf.period`
 18      where the timeframe depends on the backtesting `Context`. It should match a candle.
 19  Exit trades: It should match the candle when the buy or sell happened.
 20  """
 21  struct Trade{O<:OrderType{S} where {S<:OrderSide}, A<:AbstractAsset, E<:ExchangeID, P<:PositionSide}
 22      "The order that spawned this trade."
 23      order::Order{O,A,E,P}
 24      "The date at which the trade (usually its last order) was completed."
 25      date::DateTime
 26      "The quantity of the base currency being exchanged + (base)fees.
 27      NOTE: `amount == value / price - fees_base`, amount should already be (base)fees adjusted.
 28      Can be negative."
 29      amount::DFT
 30      "The actual price (quote currency) of the trade, after slippage."
 31      price::DFT
 32      "The value of the trade, calculated as `price * amount`."
 33      value::DFT
 34      "The fees paid for the trade.
 35      NOTE: In live mode, fees are exchange dependent, usually (for spot markets) they are in quote (sells), or base (buys) currency.
 36      In contracts they are usually in quote or settle currency.
 37      Some exchanges handle fees with multiple currencies, in those cases only the base/quote currency values are set in the `trade.fees` field,
 38      while the rest should be tracked through the (live updated) balance.
 39      Can be negative."
 40      fees::DFT
 41      "The fees paid for the trade in the base currency."
 42      fees_base::DFT
 43      "The in/out flow of quote currency, calculated as `value +/- (quote)fees`.
 44      NOTE: `size == value + fees` for `IncreaseTrade` and `size == value - fees` for `ReduceTrade`."
 45      size::DFT
 46      "The leverage the trade was executed with."
 47      leverage::DFT
 48      "The entry price of the trade."
 49      entryprice::DFT
 50      function Trade(
 51          o::Order{O,A,E,P};
 52          date,
 53          amount,
 54          price,
 55          fees,
 56          size,
 57          lev=1.0,
 58          entryprice=price,
 59          fees_base=0.0,
 60      ) where {O,A,E,P}
 61          @deassert amount > 0.0
 62          @deassert size > 0.0
 63          @deassert abs(amount) <= abs(o.amount)
 64          amount = signedamount(amount, o)
 65          value = abs(amount * price)
 66          @deassert amount == value / price - fees_base
 67          new{O,A,E,P}(
 68              o,
 69              date,
 70              amount,
 71              price,
 72              value,
 73              fees,
 74              fees_base,
 75              signedsize(size, o),
 76              lev,
 77              entryprice,
 78          )
 79      end
 80  end
 81  
 82  @doc "A type representing a trade that opens or adds to a 'long' position in a specific asset"
 83  const LongTrade{O,A,E} = Trade{O,A,E,Long}
 84  @doc "A type representing a trade that opens or adds to a 'short' position in a specific asset"
 85  const ShortTrade{O,A,E} = Trade{O,A,E,Short}
 86  @doc "A type representing a buy trade"
 87  const BuyTrade{A,E} = Trade{<:OrderType{Buy},A,E,Long}
 88  @doc "A type representing a sell trade"
 89  const SellTrade{A,E} = Trade{<:OrderType{Sell},A,E,Long}
 90  @doc "A type representing a short buy trade"
 91  const ShortBuyTrade{A,E} = Trade{<:OrderType{Buy},A,E,Short}
 92  @doc "A type representing a short sell trade"
 93  const ShortSellTrade{A,E} = Trade{<:OrderType{Sell},A,E,Short}
 94  @doc "A type representing an increase trade, which opens or increases the size of a position"
 95  const IncreaseTrade{A,E} = Union{BuyTrade{A,E},ShortSellTrade{A,E}}
 96  @doc "A type representing a reduce trade, which closes or reduces the size of a position"
 97  const ReduceTrade{A,E} = Union{SellTrade{A,E},ShortBuyTrade{A,E}}
 98  @doc "A trade type alias with position as parameter"
 99  const PositionTrade{P} = Trade{O,A,E,P} where {O<:OrderType,A<:AbstractAsset,E<:ExchangeID}
100  @doc "A type representing a liquidation trade"
101  const LiquidationTrade{S} = Trade{<:LiquidationType{S}}
102  @doc "A type representing a long liquidation trade"
103  const LongLiquidationTrade{S,A,E} = Trade{<:LiquidationType{S},A,E,Long}
104  @doc "A type representing a short liquidation trade"
105  const ShortLiquidationTrade{S,A,E} = Trade{<:LiquidationType{S},A,E,Short}
106  
107  exchangeid(::Trade{<:OrderType,<:AbstractAsset,E}) where {E<:ExchangeID} = E
108  function positionside(
109      ::Trade{<:OrderType,<:AbstractAsset,<:ExchangeID,P}
110  ) where {P<:PositionSide}
111      P
112  end
113  function orderside(
114      ::Trade{<:OrderType{S},<:AbstractAsset,<:ExchangeID,<:PositionSide}
115  ) where {S<:OrderSide}
116      S
117  end
118  ordertype(::Trade{O}) where {O<:OrderType} = O
119  islong(o::LongTrade) = true
120  islong(o::ShortTrade) = false
121  isshort(o::LongTrade) = false
122  isshort(o::ShortTrade) = true
123  @doc "Tests if the trade position side is the given position side"
124  ispos(pos::PositionSide, t::Trade) = positionside(t) == pos
125  @doc "Get the fees of a trade."
126  fees(t::Trade) = getfield(t, :fees) + getfield(t, :fees_base) * getfield(t, :price)