-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathSimulator.jl
102 lines (92 loc) · 3.75 KB
/
Simulator.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
""" perpetual swap simulator with unbiased forecasts """
struct PerpSimulator{T}
σ_oracle::T # std. of true oracle random walk
ϵ_oracle::T # std. of oracle forecast
μ_dx::T # mean of trade activity dx
σ_dx::T # std. of trade activity dx
function PerpSimulator(σ_oracle::T, ϵ_oracle::T, μ_dx::T, σ_dx::T) where {T}
new{T}(σ_oracle, ϵ_oracle, μ_dx, σ_dx)
end
end
""" simulate market for a fixed oracle price sequence """
function simulate(
f::PerpSimulator,
pₒ::Vector,
x0::Real;
policy = (res, forecast, est_net_position) -> (0, 0),
forecast_length::Int = 1,
)::Scenario
res = Scenario()
for t = 1:length(pₒ)-forecast_length
# estimate oracle price
p̂ₒ = estimate_oracle_price(f, pₒ[t:end], forecast_length)
if t == 1
# initialize market so that:
# 1. x(1) = y(1) = √k(1)
# 2. the initial market price equals the initial oracle price: Cy/x = C = pₒ
x = x0
C = pₒ[1]
k = x0^2
# make forecasts and evaluate policy
# estimate of market price: assume that C and k are fixed
dx̂ = vcat(estimate_dx(f, pₒ[1], pₒ[1]), zeros(forecast_length - 1))
x̂ = vcat(x + dx̂[1], zeros(forecast_length - 1))
p̂ₘ = vcat(C * k / x̂[1]^2, zeros(forecast_length - 1))
for i = 2:forecast_length
p̂ₘ[i] = C * k / x̂[i-1]^2
dx̂[i] = estimate_dx(f, p̂ₘ[i], p̂ₒ[i])
x̂[i] = x̂[i-1] + dx̂[i]
end
est_net_position = -dx̂
forecast = [dx̂;; x̂;; p̂ₘ;; p̂ₒ]
else
# make forecasts and evaluate policy
# estimate of market price: assume that C and k are fixed
dx̂ = vcat(
estimate_dx(f, res.mark[end], res.oracle[end]),
zeros(forecast_length - 1),
)
x̂ = vcat(res.x[end] + dx̂[1], zeros(forecast_length - 1))
p̂ₘ = vcat(res.C[end] * res.k[end] / x̂[1]^2, zeros(forecast_length - 1))
for i = 2:forecast_length
p̂ₘ[i] = res.C[end] * res.k[end] / x̂[i-1]^2
dx̂[i] = estimate_dx(f, p̂ₘ[i], p̂ₒ[i])
x̂[i] = x̂[i-1] + dx̂[i]
end
est_net_position = -dx̂
forecast = [dx̂;; x̂;; p̂ₘ;; p̂ₒ]
# evaluate policy
ΔC, Δk = policy(res, forecast, est_net_position)
# propagate market
x = res.x[end] + sample_dx(f, res.mark[end], res.oracle[end])
C = res.C[end] + ΔC
k = res.k[end] + Δk
end
update!(res, pₒ[t], x, C, k, forecast)
end
return res
end
""" Sample true oracle price as a random walk """
function sample_oracle_price(f::PerpSimulator, p₀::Real, T::Int)
p = zeros(Float64, T)
for t = 1:T
p[t] = (t == 1 ? p₀ : p[t-1] + f.σ_oracle * randn())
end
return p
end
""" Estimate the oracle price """
function estimate_oracle_price(f::PerpSimulator, pₒ::Vector, lookahead::Int)
return pₒ[1:lookahead] + f.ϵ_oracle * randn(lookahead)
end
""" Sample true trade activity dx """
function sample_dx(f::PerpSimulator, pₘ::Real, pₒ::Real)
# if oracle > mark and shorts > longs, shorts pay longs, perp collects excess
# would expect shorts to reverse their position (buy)
# therefore, increase in buying activity means dx should decrease,
# and so dx is correlated with mark - oracle
return f.μ_dx * (pₘ - pₒ) / pₒ + f.σ_dx * randn()
end
""" Estimate trade activity dx """
function estimate_dx(f::PerpSimulator, pₘ::Real, pₒ::Real)
return f.μ_dx * (pₘ - pₒ) / pₒ
end