/ LiveMode / src / orders / state.jl
state.jl
 1  using .PaperMode.Instances: amount_with_fees
 2  using Base: negate
 3  using .Executors: attr, committment, _check_unfillment, IncreaseLimitOrder, strategycash!
 4  import Base: fill!
 5  
 6  # NOTE: unfilled is always negative
 7  function fill!(::NoMarginStrategy{Live}, ai::NoMarginInstance, o::BuyOrder, t::BuyTrade)
 8      @deassert o isa IncreaseOrder && _check_unfillment(o) unfilled(o), typeof(o)
 9      @deassert committed(o) == o.attrs.committed[] && committed(o) >= 0.0
10      # from neg to 0 (buy amount is pos)
11      attr(o, :unfilled)[] += t.amount + t.fees_base
12      @deassert ltxzero(ai, attr(o, :unfilled)[], Val(:amount)) ||
13          gtxzero(ai, t.fees_base, Val(:amount)) (
14          o, attr(o, :unfilled)[], t.amount, t.fees_base
15      )
16      # from pos to 0 (buy size is neg)
17      attr(o, :committed)[] -= committment(ai, t)
18      @deassert gtxzero(ai, committed(o), Val(:price)) ||
19          o isa MarketOrder ||
20          gtxzero(ai, t.fees_base, Val(:amount)) (
21          o, committed(o), attr(o, :unfilled)[], committment(ai, t), t.fees_base, t.fees
22      )
23  end
24  function fill!(::LiveStrategy, ai::AssetInstance, o::SellOrder, t::SellTrade)
25      @deassert o isa SellOrder && _check_unfillment(o)
26      @deassert committed(o) == o.attrs.committed[] && gtxzero(ai, committed(o), Val(:amount))
27      # from pos to 0 (sell amount is neg)
28      amt = amount_with_fees(t)
29      @ifdebug if o isa AnyMarketOrder
30          @info "AMOUNT: " amt attr(o, :unfilled) attr(o, :committed) o.amount
31      end
32      attr(o, :unfilled)[] += amt
33      @deassert gtxzero(ai, attr(o, :unfilled)[], Val(:amount))
34      # from pos to 0 (sell amount is neg)
35      attr(o, :committed)[] += amt
36      @deassert gtxzero(ai, committed(o), Val(:cost)) (
37          committed(o), attr(o, :unfilled)[], t.fees, t.fees_base
38      )
39  end
40  function fill!(
41      ::MarginStrategy{Live}, ai::AssetInstance, o::ShortBuyOrder, t::ShortBuyTrade
42  )
43      @deassert o isa ShortBuyOrder && _check_unfillment(o) o
44      @deassert committed(o) == o.attrs.committed[] && ltxzero(ai, committed(o), Val(:price))
45      @deassert attr(o, :unfilled)[] < 0.0
46      amt = amount_with_fees(t)
47      attr(o, :unfilled)[] += amt # from neg to 0 (buy amount is pos)
48      @deassert ltxzero(ai, attr(o, :unfilled)[], Val(:amount))
49      # NOTE: committment is always positive except for short buy orders
50      # where that's committed is shorted (negative) asset cash
51      @deassert t.amount > 0.0 && committed(o) < 0.0 (committed(o), trades(o))
52      attr(o, :committed)[] += amt # from neg to 0 (buy amount is pos)
53      @deassert ltxzero(ai, committed(o), Val(:amount))
54  end
55  
56  @doc """ Fills an increase order for a margin strategy.
57  
58  This function fills an increase order for a margin strategy based on a given trade. 
59  It updates the unfilled and committed attributes of the order according to the trade.
60  
61  Note:
62  When entering positions, the cash committed from the trade must be downsized by leverage (at the time of the trade).
63  """
64  function fill!(
65      ::MarginStrategy{Live}, ai::MarginInstance, o::IncreaseOrder, t::IncreaseTrade
66  )
67      @deassert o isa IncreaseOrder && _check_unfillment(o) o
68      @deassert committed(o) == o.attrs.committed[] && committed(o) > 0.0 t
69      attr(o, :unfilled)[] += t.amount
70      @deassert ltxzero(ai, attr(o, :unfilled)[], Val(:amount)) || o isa ShortSellOrder
71      @deassert t.value > 0.0
72      attr(o, :committed)[] -= committment(ai, t)
73      # Market order spending can exceed the estimated committment
74      # ShortSell limit orders can spend more than committed because of slippage
75      @deassert gtxzero(ai, committed(o), Val(:price)) ||
76          o isa AnyMarketOrder ||
77          o isa IncreaseLimitOrder
78  end
79  
80  function Instances.cash!(s::LiveStrategy, ai, t::Trade)
81      @debug "trades: cash before" _module = LogWatchTrade cash(s).value cash(ai, posside(t)).value timestamp(ai, posside(t)) t.date
82      if timestamp(ai, posside(t)) <= t.date
83          @debug "trades: cash updating" _module = LogWatchTrade
84          strategycash!(s, ai, t)
85          cash!(ai, t)
86          @debug "trades: cash after" _module = LogWatchTrade cash(s).value cash(ai, posside(t)).value timestamp(ai, posside(t))
87      end
88  end