Skip to content

Commit

Permalink
Merge pull request #20 from SaguaroCapital/dev
Browse files Browse the repository at this point in the history
Rework VolumeSharesSlippageModel, expand tests
  • Loading branch information
tylerjthomas9 authored Jun 6, 2023
2 parents 69b1ced + 5b42fa2 commit 46273e9
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 18 deletions.
6 changes: 4 additions & 2 deletions src/broker/simulated_broker.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
21 changes: 11 additions & 10 deletions src/slippage_model/slippage_model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -65,32 +65,33 @@ 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

"""
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
7 changes: 7 additions & 0 deletions test/broker.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
14 changes: 8 additions & 6 deletions test/slippage_model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 46273e9

Please sign in to comment.