module.jl
1 using ExchangeTypes 2 import ExchangeTypes: exchangeid 3 using Instruments 4 using Instruments: Misc 5 import Base: == 6 7 using .Misc: config, PositionSide, Long, Short, TimeTicks, Lang 8 using .Misc.DocStringExtensions 9 import .Misc: opposite 10 using .TimeTicks 11 using .ExchangeTypes: Exchange 12 13 @doc """ Abstract type representing an event in an exchange 14 Types implementing an `ExchangeEvent` must have a `tag::Symbol` field. 15 Every instance of such event should have a unique tag and an optional group. 16 """ 17 abstract type ExchangeEvent{E} end 18 19 function event!( 20 exc::Exchange, 21 kind::Type{<:ExchangeEvent}, 22 tag, 23 group; 24 event_date=now(), 25 this_date=now(), 26 kwargs..., 27 ) 28 ev = kind{exc.id}(Symbol(tag), Symbol(group), NamedTuple(k => v for (k, v) in kwargs)) 29 push!(exc._trace, ev; event_date, this_date) 30 end 31 32 function event!(exc::Exchange, ev::ExchangeEvent; event_date=now(), this_date=now()) 33 push!(exc._trace, ev; event_date, this_date) 34 end 35 36 @doc """Records an event in the exchange's trace. """ 37 event!(v, args...; kwargs...) = event!(exchange(v), args...; kwargs...) 38 39 struct AssetEvent{E} <: ExchangeEvent{E} 40 tag::Symbol 41 group::Symbol 42 data::NamedTuple 43 end 44 struct StrategyEvent{E} <: ExchangeEvent{E} 45 tag::Symbol 46 group::Symbol 47 data::NamedTuple 48 end 49 50 @doc """ Abstract type representing the side of an order """ 51 abstract type OrderSide end 52 @doc """ Abstract type representing the buy side of an order """ 53 abstract type Buy <: OrderSide end 54 @doc """ Abstract type representing the sell side of an order """ 55 abstract type Sell <: OrderSide end 56 @doc """ Abstract type representing both sides of an order """ 57 abstract type BuyOrSell <: OrderSide end 58 59 @doc """ Abstract type representing the type of an order """ 60 abstract type OrderType{S<:OrderSide} end 61 @doc """ Abstract type representing any limit order """ 62 abstract type LimitOrderType{S} <: OrderType{S} end 63 @doc """ Abstract type representing any immediate order """ 64 abstract type ImmediateOrderType{S} <: LimitOrderType{S} end 65 @doc """ Abstract type representing GTC (good till cancel) orders """ 66 abstract type GTCOrderType{S} <: LimitOrderType{S} end 67 @doc """ Abstract type representing post only orders""" 68 abstract type PostOnlyOrderType{S} <: GTCOrderType{S} end 69 @doc """ Abstract type representing FOK (fill or kill) orders """ 70 abstract type FOKOrderType{S} <: ImmediateOrderType{S} end 71 @doc """ Abstract type representing IOC (immediate or cancel) orders """ 72 abstract type IOCOrderType{S} <: ImmediateOrderType{S} end 73 @doc """ Abstract type representing market orders """ 74 abstract type MarketOrderType{S} <: OrderType{S} end 75 @doc """ Abstract type representing liquidation orders """ 76 abstract type LiquidationType{S} <: MarketOrderType{S} end 77 @doc """ Abstract type representing forced orders """ 78 abstract type ForcedOrderType{S} <: MarketOrderType{S} end 79 80 @doc """An Order is a container for trades, tied to an asset and an exchange. 81 Its execution depends on the order implementation. 82 83 $(FIELDS) 84 85 `date`: the time at which the strategy requested the order. 86 The strategy is assumed to have *knowledge* of the ohlcv data \ 87 strictly lower than the timeframe adjusted date. 88 Example: 89 ```julia 90 ts = dt"2020-05-24T02:34:00" # the date of the order request 91 tf = @infertf ohlcv # get the timeframe (15m) 92 start_date = ohlcv.timestamp[begin] 93 stop_date = apply(tf, ts) # normalize date to timeframe 94 stop_date -= tf.period # scale down by one timeframe step 95 # At this point the stop date would be `2020-05-24T02:30:00` 96 # which covers the period between ...02:30:00..02:45:00... 97 # Therefore the strategy can only have access to data < 02:30:00 98 avail_ohlcv = ohlcv[DateRange(start_date, stop_date), :] 99 @assert isless(avail_ohlcv.timestamp[end], dt"2020-05-24T02:30:00") 100 @assert isequal(avail_ohlcv.timestamp[end] + tf.period, dt"2020-05-24T02:30:00") 101 ``` 102 """ 103 struct Order{ 104 T<:OrderType{S} where {S<:OrderSide},A<:AbstractAsset,E<:ExchangeID,P<:PositionSide 105 } 106 asset::A 107 exc::E 108 date::DateTime 109 price::Float64 110 amount::Float64 111 id::String 112 tag::String 113 attrs::NamedTuple 114 end 115 116 @doc """ Creates an Order object. 117 118 $(TYPEDSIGNATURES) 119 120 This function constructs an Order object with the given parameters. 121 The Order object represents a trade order tied to an asset and an exchange. 122 The execution of the order depends on the order implementation. 123 The function takes in parameters for the asset, exchange, order type, position side, price, date, amount, attributes, and an optional id. 124 125 """ 126 function Order( 127 a::A, 128 e::E, 129 ::Type{Order{T}}, 130 ::Type{P}=Long; 131 price, 132 date, 133 amount, 134 attrs=(;), 135 id="", 136 tag="", 137 kwargs..., 138 ) where {T<:OrderType,A<:AbstractAsset,E<:ExchangeID,P<:PositionSide} 139 Order{T,A,E,P}(a, e, date, price, amount, id, tag, attrs) 140 end 141 function Order( 142 a, e, ::Type{Order{T,<:AbstractAsset,<:ExchangeID,P}}; kwargs... 143 ) where {T<:OrderType,P<:PositionSide} 144 Order(a, e, Order{T}, P; kwargs...) 145 end 146 Base.hash(o::Order{T}) where {T} = hash((T, o.asset, o.exc, o.date, o.price, o.amount)) 147 function Base.hash(o::Order{T}, h::UInt) where {T} 148 hash((T, o.asset, o.exc, o.date, o.price, o.amount), h) 149 end 150 @doc """ Compares two Order objects based on their date. 151 152 $(TYPEDSIGNATURES) 153 154 This function compares the date of two Order objects and returns `true` if the date of the first Order is less than the date of the second Order. It is used to sort or compare Orders based on their date. 155 156 """ 157 Base.isless(o1::O1, o2::O2) where {O1,O2<:Order} = isless(o1.date, o2.date) 158 @doc """ Get the fees of an order. 159 160 $(TYPEDSIGNATURES) 161 162 This function returns the total fees of an order, which is the sum of the fees of all trades associated with the order. 163 """ 164 fees(o::Order) = 165 let tds = trades(o) 166 if isempty(tds) 167 nothing 168 else 169 sum(fees(t) for t in tds) 170 end 171 end 172 173 @doc "An order that increases the size of a position." 174 const BuyOrder{A,E} = Order{<:OrderType{Buy},A,E,Long} 175 @doc "An order that decreases the size of a position." 176 const SellOrder{A,E} = Order{<:OrderType{Sell},A,E,Long} 177 @doc "A type representing any order that involves buying, regardless of the specific order type or position side" 178 const AnyBuyOrder{P,A,E} = Order{<:OrderType{Buy},A,E,P} 179 @doc "A type representing any order that involves selling, regardless of the specific order type or position side" 180 const AnySellOrder{P,A,E} = Order{<:OrderType{Sell},A,E,P} 181 @doc "A type representing an order that opens or adds to a 'long' position in a specific asset" 182 const LongOrder{O,A,E} = Order{O,A,E,Long} 183 @doc "A type representing an order that opens or adds to a 'short' position in a specific asset" 184 const ShortOrder{O,A,E} = Order{O,A,E,Short} 185 @doc "A type representing a buy order that opens or adds to a 'short' position in a specific asset" 186 const ShortBuyOrder{A,E} = Order{<:OrderType{Buy},A,E,Short} 187 @doc "A type representing a sell order that opens or adds to a 'short' position in a specific asset" 188 const ShortSellOrder{A,E} = Order{<:OrderType{Sell},A,E,Short} 189 @doc "A type representing any immediate order, regardless of the specific asset, exchange, or position side" 190 const AnyImmediateOrder{A,E,P} = Order{<:ImmediateOrderType,A,E,P} 191 192 @doc "An order that increases the size of a position." 193 const IncreaseOrder{A,E} = Union{BuyOrder{A,E},ShortSellOrder{A,E}} 194 @doc "An order that decreases the size of a position." 195 const ReduceOrder{A,E} = Union{SellOrder{A,E},ShortBuyOrder{A,E}} 196 @doc "A Market Order type that liquidates a position." 197 const LiquidationOrder{S,P,A<:AbstractAsset,E<:ExchangeID} = Order{LiquidationType{S},A,E,P} 198 @doc "A Market Order type called when manually closing a position (to sell the holdings)." 199 const LongReduceOnlyOrder{A<:AbstractAsset,E<:ExchangeID} = Order{ 200 ForcedOrderType{Sell},A,E,Long 201 } 202 const ShortReduceOnlyOrder{A<:AbstractAsset,E<:ExchangeID} = Order{ 203 ForcedOrderType{Buy},A,E,Short 204 } 205 const ReduceOnlyOrder = Union{LongReduceOnlyOrder,ShortReduceOnlyOrder} 206 207 @doc """ Defines various order types in the trading system 208 209 $(TYPEDSIGNATURES) 210 211 This macro is used to define various order types in the trading system. It takes a boolean value to determine if the order type is a super type, and a list of types to be defined. 212 213 """ 214 macro deforders(issuper, types...) 215 @assert issuper isa Bool 216 out = quote end 217 for t in types 218 type_str = string(t) 219 order_type_str = type_str * "Order" 220 type_sym = Symbol(order_type_str) 221 short_type_sym = Symbol("Short" * order_type_str) 222 # HACK: const/types definitions inside macros can't be revised 223 isdefined(@__MODULE__, type_sym) && continue 224 type = esc(type_sym) 225 short_type = esc(short_type_sym) 226 ordertype = esc(Symbol(type_str * "OrderType")) 227 _orderexpr(pos_side) = 228 if issuper 229 :(Order{<:$ordertype{S},A,E,$pos_side}) 230 else 231 :(Order{$ordertype{S},A,E,$pos_side}) 232 end 233 long_orderexpr = _orderexpr(Long) 234 short_orderexpr = _orderexpr(Short) 235 push!( 236 out.args, 237 quote 238 const $type{S<:OrderSide,A<:AbstractAsset,E<:ExchangeID} = $long_orderexpr 239 const $short_type{S<:OrderSide,A<:AbstractAsset,E<:ExchangeID} = 240 $short_orderexpr 241 export $type, $short_type 242 end, 243 ) 244 end 245 out 246 end 247 @deforders false GTC PostOnly FOK IOC Market 248 @deforders true Limit 249 250 ==(v1::Type{<:OrderSide}, v2::Type{BuyOrSell}) = true 251 ==(v1::Type{BuyOrSell}, v2::Type{<:OrderSide}) = true 252 @doc """Get the `OrderType` of an order """ 253 ordertype(::Order{T}) where {T<:OrderType} = T 254 ordertype(::Type{<:Order{T}}) where {T<:OrderType} = T 255 @doc """Get the `PositionSide` of an order """ 256 function positionside( 257 ::Union{Type{O},O} 258 ) where {O<:Order{T,<:AbstractAsset,<:ExchangeID,P}} where {T,P} 259 P 260 end 261 positionside(::Union{P,Type{P}}) where {P<:PositionSide} = P 262 @doc """Get the price and time of an order """ 263 pricetime(o::Order) = (price=o.price, time=o.date) 264 @doc """Get the `ExchangeID` of an order """ 265 exchangeid(::Order{<:OrderType,<:AbstractAsset,E}) where {E<:ExchangeID} = E 266 commit!(args...; kwargs...) = error("not implemented") 267 @doc """Get the opposite side of an order """ 268 opposite(::Type{Buy}) = Sell 269 opposite(::Type{Sell}) = Buy 270 function opposite(::Type{T}) where {S,T<:OrderType{S}} 271 getfield(T.name.module, T.name.name){opposite(S)} 272 end 273 @doc """Get the liquidation side of an order """ 274 liqside(::Union{Long,Type{Long}}) = Sell 275 liqside(::Union{Short,Type{Short}}) = Buy 276 @doc """Is the order a liquidation order""" 277 isliquidation(::Order{O}) where {O<:OrderType} = O == LiquidationType 278 sidetopos(::Order{<:OrderType{Buy}}) = Long 279 sidetopos(::Order{<:OrderType{Sell}}) = Short 280 @doc """Test if an order is a long order""" 281 islong(p::Union{<:T,<:Type{<:T}}) where {T<:PositionSide} = p == Long() 282 @doc """Test if an order is a short order""" 283 isshort(p::Union{<:T,<:Type{<:T}}) where {T<:PositionSide} = p == Short() 284 islong(o::Union{<:LongOrder,<:Type{<:LongOrder}}) = true 285 islong(o::Union{<:ShortOrder,<:Type{<:ShortOrder}}) = false 286 isshort(o::Union{<:LongOrder,<:Type{<:LongOrder}}) = false 287 isshort(o::Union{<:ShortOrder,<:Type{<:ShortOrder}}) = true 288 islong(::Nothing) = false 289 isshort(::Nothing) = false 290 @doc """Test if an order is an immediate order""" 291 isimmediate(::Order{<:Union{ImmediateOrderType,MarketOrderType}}) = true 292 isimmediate(::Order) = false 293 @doc """Test if the order position side matches the given position side""" 294 ispos(pos::PositionSide, o::Order) = positionside(o)() == pos 295 order!(args...; kwargs...) = error("not implemented") 296 @doc """Get the trades history of an order """ 297 trades(args...; kwargs...) = error("not implemented") 298 299 include("trades.jl") 300 include("positions.jl") 301 include("balance.jl") 302 include("ohlcv.jl") 303 include("errors.jl") 304 include("print.jl") 305 306 @doc "Dispatch by `OrderSide` or by an `Order` or `Trade` with the same side as parameter." 307 const BySide{S<:OrderSide} = Union{ 308 S,Type{S},Order{<:OrderType{S}},Type{<:Order{<:OrderType{S}}},Trade{<:OrderType{S}} 309 } 310 @doc "A type representing any order with a specific position side" 311 const AnyOrderPos{P<:PositionSide} = 312 Union{O,Type{O}} where {O<:Order{<:OrderType,<:AbstractAsset,<:ExchangeID,P}} 313 @doc "A type representing any trade with a specific position side" 314 const AnyTradePos{P<:PositionSide} = 315 Union{T,Type{T}} where {T<:Trade{<:OrderType,<:AbstractAsset,<:ExchangeID,P}} 316 @doc "Dispatch by `PositionSide` or by an `Order` or `Trade` with the same position side as parameter." 317 const ByPos{P<:PositionSide} = Union{P,Type{P},AnyOrderPos{P},AnyTradePos{P}} 318 319 # NOTE: Implementing this function for `ByPos` breaks backtesting, don't do it! 320 orderside(::BySide{S}) where {S<:OrderSide} = S 321 isside(what::ByPos{Long}, side::ByPos{Long}) = true 322 isside(what::ByPos{Short}, side::ByPos{Short}) = true 323 @doc "Test if the order side matches the given side" 324 isside(args...) = false 325 @doc """`Buy` as `Long` and `Sell` as `Short`""" 326 sidetopos(::BySide{Buy}) = Long() 327 sidetopos(::BySide{Sell}) = Short() 328 postoside(::ByPos{Long}) = Buy 329 postoside(::ByPos{Short}) = Sell 330 331 ReduceOnlyOrder(::ByPos{Long}) = LongReduceOnlyOrder 332 ReduceOnlyOrder(::ByPos{Long}, A) = LongReduceOnlyOrder{A} 333 ReduceOnlyOrder(::ByPos{Long}, A, E) = LongReduceOnlyOrder{A,E} 334 ReduceOnlyOrder(::ByPos{Short}) = ShortReduceOnlyOrder 335 ReduceOnlyOrder(::ByPos{Short}, A) = ShortReduceOnlyOrder{A} 336 ReduceOnlyOrder(::ByPos{Short}, A, E) = ShortReduceOnlyOrder{A,E} 337 338 export Order, OrderType, OrderSide, BySide, Buy, Sell, BuyOrSell, Trade, ByPos 339 export BuyOrder, SellOrder, BuyTrade, SellTrade, AnyBuyOrder, AnySellOrder 340 export ShortBuyTrade, ShortSellTrade 341 export LongOrder, ShortOrder, ShortBuyOrder, ShortSellOrder 342 export IncreaseOrder, ReduceOrder, IncreaseTrade, ReduceTrade, AnyImmediateOrder 343 export LiquidationOrder, ReduceOnlyOrder 344 export OrderError, NotEnoughCash, NotFilled, NotMatched, OrderTimeOut 345 export OrderFailed, OrderCanceled, LiquidationOverride 346 export orderside, positionside, pricetime, islong, isshort, ispos, isimmediate, isside 347 export liqside, sidetopos, opposite 348 export event!, 349 ExchangeEvent, 350 AssetEvent, 351 StrategyEvent, 352 PositionEvent, 353 PositionUpdated, 354 MarginUpdated, 355 LeverageUpdated, 356 BalanceUpdated, 357 OHLCVUpdated 358 export fees