diff --git a/src/broker/simulated_broker.jl b/src/broker/simulated_broker.jl index a8c173d..a9546b3 100644 --- a/src/broker/simulated_broker.jl +++ b/src/broker/simulated_broker.jl @@ -84,7 +84,7 @@ end function withdraw_funds!(broker::Broker, amount::Real, currency::String) @assert amount >= 0 "Can not debit negative amount: $amount" - @assert currency in broker.cash_balances "Unknown currency $currency" + @assert currency in keys(broker.cash_balances) "Unknown currency $currency" error_msg = "Can not withdraw $amount, because it is more than the cash balance of $(broker.cash_balances[currency])" @assert amount <= broker.cash_balances[currency] error_msg @@ -186,7 +186,9 @@ function _execute_order(broker::Broker, dt::DateTime, portfolio_id::String, orde else # sell price = bid_ask[1] end - price = broker.slippage_model(order.direction; price, volume) + price = broker.slippage_model( + order.direction; price, volume, order_quantity=order.quantity + ) consideration = round(price * order.quantity; digits=2) fee = calculate_fee(broker.fee_model, order.quantity, price) diff --git a/src/slippage_model/slippage_model.jl b/src/slippage_model/slippage_model.jl index 41aee2f..cdc3603 100644 --- a/src/slippage_model/slippage_model.jl +++ b/src/slippage_model/slippage_model.jl @@ -17,7 +17,7 @@ Returns struct ZeroSlippageModel <: SlippageModel end function (slippage_model::ZeroSlippageModel)( - direction::Int; price::Float64=0.0, volume::Float64=0.0 + direction::Int; price::Float64=0.0, volume::Float64=0.0, order_quantity::Real=0.0 ) return price end @@ -41,7 +41,7 @@ struct FixedSlippageModel <: SlippageModel end function (slippage_model::FixedSlippageModel)( - direction::Int; price::Float64=0.0, volume::Float64=0.0 + direction::Int; price::Float64=0.0, volume::Float64=0.0, order_quantity::Real=0.0 ) return price + (slippage_model.spread / 2.0) * direction end @@ -65,7 +65,7 @@ struct PercentSlippageModel <: SlippageModel end function (slippage_model::PercentSlippageModel)( - direction::Int; price::Float64=0.0, volume::Float64=0.0 + direction::Int; price::Float64=0.0, volume::Float64=0.0, order_quantity::Real=0.0 ) return price + ((slippage_model.slippage_pct / 100) * price / 2.0) * direction end @@ -73,24 +73,25 @@ end """ Slippage is based on the ratio of order volume to total volume -Buy orders will execute at `ask * (1 + (volume_shares_pct/100) * order.volume / total_volume)` -Sell orders will execute at `bid * (1 - (volume_shares_pct/100) * order.volume / total_volume)` +Buy orders will execute at `ask + (volume_share^2 * price_impact * price * direction)` +Sell orders will execute at `bid - (volume_share^2 * price_impact * price * direction)` Fields ------ -- `volume_shares_pct::Float64` +- `price_impact::Float64=0.1` - The scaling coefficient for price impact. Larger values will result in larger price impacts. Returns ------- - `Float64`: The price including slippage """ struct VolumeSharesSlippageModel <: SlippageModel - volume_shares_pct::Float64 + price_impact::Float64 end function (slippage_model::VolumeSharesSlippageModel)( - direction::Int; price::Float64=0.0, volume::Float64=0.0 + direction::Int; price::Float64=0.0, volume::Float64=0.0, order_quantity::Real=0.0 ) - ratio = order.volume / volume - return price + ((slippage_model.volume_shares_pct / 100) * price * ratio) * direction + volume_share = order_quantity / volume + simulated_impact = volume_share^2 * slippage_model.price_impact * price * direction + return price + simulated_impact end diff --git a/test/broker.jl b/test/broker.jl index 9cc14fb..0c6873e 100644 --- a/test/broker.jl +++ b/test/broker.jl @@ -26,4 +26,11 @@ @test broker.portfolios["test_port"].cash == 75198.0 withdraw_funds_from_portfolio!(broker, "test_port", 5_000) @test broker.portfolios["test_port"].cash == 70198.0 + subscribe_funds!(broker, 25_000, "USD") + @test broker.cash_balances["USD"] == 50_000.0 + withdraw_funds!(broker, 25_000, "USD") + @test broker.cash_balances["USD"] == 25_000.0 + + @test SaguaroTrader.get_total_market_value(broker) == 4802.0 + @test SaguaroTrader.get_account_total_equity(broker) == 100000.0 end diff --git a/test/slippage_model.jl b/test/slippage_model.jl index 89ef141..7a06360 100644 --- a/test/slippage_model.jl +++ b/test/slippage_model.jl @@ -23,10 +23,12 @@ @test slippage_model(1; price) == 10.01 # VolumeSharesSlippageModel - slippage_model = PercentSlippageModel(0.0) - @test slippage_model(-1; price) == 10.0 - slippage_model = PercentSlippageModel(0.2) - @test slippage_model(-1; price) == 9.99 - slippage_model = PercentSlippageModel(0.2) - @test slippage_model(1; price) == 10.01 + slippage_model = VolumeSharesSlippageModel(0.0) + volume = 1e7 + order_quantity = 10_000.0 + @test slippage_model(-1; price, volume, order_quantity) == 10.0 + @test slippage_model(1; price, volume, order_quantity) == 10.0 + slippage_model = VolumeSharesSlippageModel(0.2) + @test slippage_model(-1; price, volume, order_quantity) == 9.999998 + @test slippage_model(1; price, volume, order_quantity) == 10.000002 end