-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPurchaseGenerator.m
139 lines (112 loc) · 5.05 KB
/
PurchaseGenerator.m
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
classdef PurchaseGenerator < handle
% Generate a random purchase for a LiquidityPool
% If the Token is an algoritmic stablecoin two different stochastic
% models are implemented: one related to price stability, the other
% for peg loss situations
properties
Pool LiquidityPool
P double
sigma double
i
WalletBalanceGenerator WalletBalanceGenerator
CrisisScenario double = 0
end
methods
function generator = PurchaseGenerator(liquidityPool, length, ...
initialP, initialSigma, walletBalanceGenerator)
% PARAMS
% liquidity pool - LiquidityPool
% number of simulation iterations - decimal
% starting probability - double
% starting sigma - double
% wallet balance generator - WalletBalanceGenerator
generator.Pool = liquidityPool;
generator.P = zeros(1, length);
generator.P(1) = initialP;
generator.sigma = initialSigma;
generator.i = 1;
generator.WalletBalanceGenerator = walletBalanceGenerator;
end
function [token, quantity] = rndPurchase(self, totalFreeTokenSupply, totalTokenSupply)
% generate random tokens purchase
% compute ratio between free and total tokens
r = totalFreeTokenSupply / totalTokenSupply;
% compute delta
delta = self.computeDelta();
% add delta to P
self.i = self.i + 1;
newP = self.P(self.i-1) + delta;
% is the new P beetwen 0 and 1?
if (newP > 1)
self.P(self.i) = 1;
elseif (newP < 0)
self.P(self.i) = 0;
else
self.P(self.i) = newP;
end
% choose a n from a random uniform distribution
n = rand(1,1);
if (n < self.P(self.i))
token = self.Pool.T_a;
tokenPrice = self.Pool.getTokenPrice(self.Pool.T_a, 1);
else
token = self.Pool.T_b;
tokenPrice = 1;
end
quantity = self.generateRandomQuantity(r, tokenPrice);
if (token.is_equal(self.Pool.T_a) && quantity > totalFreeTokenSupply)
quantity = totalFreeTokenSupply;
end
end
function delta = computeDelta(self)
% COMPUTE DELTA from a normal distribution
normMean = 0;
computedSigma = self.sigma;
if (self.Pool.T_a.IsStablecoin == true)
% get price deviation from peg
priceDeviation = self.Pool.T_a.PEG - self.Pool.getTokenPrice(self.Pool.T_a, 1);
if (priceDeviation > 0.05)
self.CrisisScenario = priceDeviation;
% the mean of the normal distribution is moved
computedSigma = computedSigma * 10;
normMean = priceDeviation * computedSigma;
else
self.CrisisScenario = 0;
end
elseif (self.Pool.T_a.IsCollateral == true && self.CrisisScenario > 0)
normMean = self.CrisisScenario * computedSigma;
end
delta = normrnd(normMean, computedSigma);
end
function quantity = generateRandomQuantity(self, r, tokenPrice)
% select a random wallet from the wallets distribution
randomWalletBalance = ...
self.WalletBalanceGenerator.rndWalletBalance();
realBalance = (randomWalletBalance / tokenPrice) * r;
% set sigma
if self.Pool.T_a.IsCollateral == true
sigmaQuantity = realBalance;
sigmaQuantity = sigmaQuantity * self.sigma*10000;
else
sigmaQuantity = realBalance/100;
sigmaQuantity = sigmaQuantity * self.sigma*10000;
end
% compute price deviation from peg
if (self.CrisisScenario > 0)
sigmaQuantity = realBalance / 5;
end
if realBalance > 0
% compute the truncated normal distribution
untruncated = makedist('Normal', 0, sigmaQuantity);
tnd = truncate(untruncated, 0, realBalance);
% get random quantity
quantity = random(tnd, 1, 1);
else
quantity = 0;
end
end
function setNewSigma(self, newSigma)
self.sigma = newSigma;
end
end
end