math file

This commit is contained in:
dapplion 2019-08-04 13:29:54 +02:00
parent 54d673b14e
commit 3fe4fb5c82
3 changed files with 106 additions and 35 deletions

View File

@ -17,6 +17,12 @@ import PriceSimulationChart from "./PriceSimulationChart";
import HelpText from "./HelpText";
// Utils
import { getLast, getAvg, pause } from "./utils";
import {
getInitialParams,
getPriceR,
getRandomDeltas,
getSlippage
} from "./math";
import { throttle } from "lodash";
// General styles
import "./app.css";
@ -84,7 +90,7 @@ export default function App() {
const [curveParams, setCurveParams] = useState({
d0: 1e6, // Initial raise, d0 (DAI)
theta: 0.35, // fraction allocated to reserve (.)
p0: 0.1, // Hatch sale Price p0 (DAI / token)
p0: 0.1, // Hatch sale price p0 (DAI / token)
returnF: 3, // Return factor (.)
wFee: 0.05 // friction coefficient (.)
});
@ -101,10 +107,17 @@ export default function App() {
);
// Simulation results
const k = returnF / (1 - theta); // Invariant power kappa (.)
const R0 = (1 - theta / 100) * d0; // Initial reserve (DAI)
const S0 = d0 / p0; // initial supply of tokens (token)
const V0 = S0 ** k / R0; // invariant coef
const {
k, // Invariant power kappa (.)
R0, // Initial reserve (DAI)
S0, // initial supply of tokens (token)
V0 // invariant coef
} = getInitialParams({
d0,
theta,
p0,
returnF
});
const [priceTimeseries, setPriceTimeseries] = useState([0]);
const [withdrawFeeTimeseries, setWithdrawFeeTimeseries] = useState([0]);
@ -141,8 +154,7 @@ export default function App() {
let canContinueSimulation = true;
async function simulateRandomDelta() {
const R_t: number[] = [R0];
const S_t: number[] = [S0];
const p_t: number[] = [R0 / S0];
const p_t: number[] = [getPriceR({ R: R0, V0, k })];
const wFee_t: number[] = [0];
const slippage_t: number[] = [];
@ -151,37 +163,20 @@ export default function App() {
const updateEveryNth = 1;
// Compute the random deltas
const deltaR_t: number[] = [];
for (let i = 0; i < numSteps; i++) {
const rand = 1 - 2 * Math.random();
const sin = Math.sin((1 / 20) * (i / numSteps));
const ascending = Math.sin((Math.PI / 1) * (i / numSteps));
const deltaR = 1e5 * rand + 1e5 * sin + 2e4 * ascending;
deltaR_t.push(deltaR);
}
// Normalize random deltas with the average transaction size
const deltaR_avg = getAvg(deltaR_t);
const deltaR_t_normalized = deltaR_t.map(
(deltaR: number) => (avgTxSize * deltaR) / deltaR_avg
);
const deltaR_t = getRandomDeltas({ numSteps, avgTxSize });
setSimulationRunning(true);
for (let i = 0; i < numSteps; i++) {
const deltaR = deltaR_t_normalized[i];
const deltaR = deltaR_t[i];
// Protect against too strong negative deltas
const R = getLast(R_t);
const S = getLast(S_t);
const p = getLast(p_t);
const R_next = R + deltaR;
const deltaS = (V0 * (R + deltaR)) ** (1 / k) - S;
const S_next = S + deltaS;
R_t.push(R_next);
S_t.push(S_next);
p_t.push(R_next / S_next);
p_t.push(getPriceR({ R: R_next, V0, k }));
slippage_t.push(getSlippage({ R, deltaR, V0, k }));
// Consider withdraw fees on sales only
if (deltaR < 0) {
wFee_t.push(getLast(wFee_t) - deltaR * wFee);
@ -190,12 +185,6 @@ export default function App() {
wFee_t.push(getLast(wFee_t));
}
const p_next = getLast(p_t);
// const realizedPrice = deltaR / deltaS;
const spotPrice = p;
const slippage = Math.abs(p_next - spotPrice) / spotPrice / 2;
slippage_t.push(slippage);
// Stop the simulation if it's no longer active
if (!simulationActive || !canContinueSimulation) break;

View File

@ -1,4 +1,5 @@
#root {
background-color: #152128;
min-height: 100vh;
margin: 0;
}

81
src/math.ts Normal file
View File

@ -0,0 +1,81 @@
import { getAvg } from "./utils";
/**
* Computes the initial params given the "user friendly" params:
* - Initial raise, `d0` (DAI)
* - fraction allocated to reserve, `theta`
* - Hatch sale price, `p0` (DAI / token)
* - Return factor, `returnF`
*/
export function getInitialParams({
d0,
theta,
p0,
returnF
}: {
d0: number;
theta: number;
p0: number;
returnF: number;
}) {
const k = returnF / (1 - theta); // Invariant power kappa (.)
const R0 = (1 - theta) * d0; // Initial reserve (DAI)
const S0 = d0 / p0; // initial supply of tokens (token)
const V0 = S0 ** k / R0; // invariant coef
return { k, R0, S0, V0 };
}
/**
* Computes the price at a specific reserve `R`
*/
export function getPriceR({ R, V0, k }: { R: number; V0: number; k: number }) {
return (k * R ** ((k - 1) / k)) / V0 ** (1 / k);
}
/**
* Compute slippage at a point `R`, given a `deltaR`
*/
export function getSlippage({
R,
deltaR,
V0,
k
}: {
R: number;
deltaR: number;
V0: number;
k: number;
}) {
const S = (V0 * R) ** (1 / k);
const deltaS = (V0 * (R + deltaR)) ** (1 / k) - S;
const realizedPrice = deltaR / deltaS;
const spotPrice = getPriceR({ R, V0, k });
return Math.abs(realizedPrice - spotPrice) / spotPrice;
}
/**
* Generate a random delta given three components:
* 1. Climbing sin
* 2. Oscilating sin
* 3. Random component
*/
export function getRandomDeltas({
numSteps,
avgTxSize
}: {
numSteps: number;
avgTxSize: number;
}) {
const deltaR_t: number[] = [];
for (let i = 0; i < numSteps; i++) {
const rand = 1 - 2 * Math.random();
const sin = Math.sin((1 / 20) * (i / numSteps));
const ascending = Math.sin((Math.PI / 1) * (i / numSteps));
const deltaR = 1e5 * rand + 1e5 * sin + 2e4 * ascending;
deltaR_t.push(deltaR);
}
// Normalize random deltas with the average transaction size
const deltaR_avg = getAvg(deltaR_t);
return deltaR_t.map((deltaR: number) => (avgTxSize * deltaR) / deltaR_avg);
}