Skip to content

Instantly share code, notes, and snippets.

@sambacha
Created February 21, 2025 20:58
Show Gist options
  • Save sambacha/09f630a22d340c23f4e7a2370744f98c to your computer and use it in GitHub Desktop.
Save sambacha/09f630a22d340c23f4e7a2370744f98c to your computer and use it in GitHub Desktop.
Chitra Airdrop Python script
import argparse
import numpy as np
from scipy.optimize import fsolve
def payoff(Pt, C, tau_s, r):
"""Calculates the payoff of the airdrop for a single user.
Args:
Pt: Asset price at time t.
C: Capital committed by the user at time tau_s.
tau_s: Random stopping time (airdrop time).
r: risk free rate
Returns:
The payoff, which is max(e^(-r*tau_s) * Pt * C - C, 0). Simplified.
"""
return max(np.exp(-r * tau_s) * Pt - 1, 0) * C
def hurdle_rate_multiplier(r, sigma):
"""Calculates the hurdle rate multiplier (phi).
Args:
r: Risk-free interest rate.
sigma: Volatility of the asset price.
Returns:
The hurdle rate multiplier (phi).
"""
def equation(a):
return 2 * a**2 - (2 * r / sigma**2 + 1) * a + 0.5
# Find the root that leads to a positive hurdle rate
a_roots = fsolve(equation, [0, 1]) # Provide initial guesses
a = a_roots[np.argmin(np.abs(a_roots- 0.5))] # get the lowest
phi = (np.sqrt(1 + 4 * (1/a)) - 1) / (1/a) - 3/2.
return phi
def hurdle_rate(C, r, sigma):
"""Calculates the hurdle rate Li(t). Here, assuming t=gamma^-1
Args:
C: Capital committed.
r: risk free rate.
sigma: Volatility
Returns: hurdle_rate Li
"""
phi = hurdle_rate_multiplier(r, sigma)
return (phi + 1) * C
def expected_exercise_time_simplified(x, L, nu, sigma_squared):
"""Calculates a simplified expected exercise time (O notation).
Args:
x: initial price.
L: Hurdle Rate.
nu: mu - sigma^2 / 2
sigma_squared: sigma squared
Returns:
An approximation of the expected exercise time. O(nu) (x/L)^(-O(1))
This version makes simplifying assumptions.
"""
#These need to be sufficiently large for the simplifications
if sigma_squared >= nu**2:
return (x / L)**(-2) / nu # Use -2 as a stand-in for -Theta(1)
else:
return np.inf
def expected_exercise_time(x, L, mu, sigma, gamma, simplified=True):
"""Calculates the expected exercise time.
Args:
x: Initial price (X0).
L: Hurdle rate (Li(gamma^-1)).
mu: Drift of the asset price.
sigma: Volatility of the asset price.
gamma: Parameter of the exponential distribution for tau_s.
simplified: calculate simplified version.
Returns:
The expected exercise time (E[T*]).
"""
nu = mu - sigma**2 / 2
if simplified:
return expected_exercise_time_simplified(x, L, nu, sigma**2)
# Full calculation (more complex, less intuitive)
if x >= L:
alpha = (2 * gamma) / (np.sqrt(nu**2 + 2 * gamma * sigma**2) - nu)
return (
(nu**2 + gamma * sigma**2 - nu * np.sqrt(nu**2 + 2 * gamma * sigma**2))
/ (2 * nu * gamma**2)
* (x / L) ** (-alpha)
+ 1 / gamma
)
else: # x < L
term1 = ((np.sqrt(nu**2 + 2 * gamma * sigma**2) - nu) ** 2) / (
4 * nu * gamma**2
)
term2 = (sigma**2 / (2 * nu)) * np.log(x/L)
term3 = ((sigma**2 / (nu * (np.sqrt(nu**2 + 2*gamma*(sigma**2)) - nu) ) ) * (x/L)**( (2*nu) / (np.sqrt(nu**2 + 2*gamma*sigma**2) - nu) ) -1 )
return term1 * (term2+term3) + 1/gamma
def main():
parser = argparse.ArgumentParser(
description="Calculate metrics for a retroactive airdrop."
)
parser.add_argument(
"--initial_price", type=float, required=True, help="Initial asset price (X0)."
)
parser.add_argument(
"--capital", type=float, required=True, help="Capital committed by the user."
)
parser.add_argument(
"--mu", type=float, required=True, help="Drift of the asset price."
)
parser.add_argument(
"--sigma", type=float, required=True, help="Volatility of the asset price."
)
parser.add_argument(
"--gamma", type=float, required=True, help="Parameter of the exponential distribution for tau_s."
)
parser.add_argument(
"--risk_free_rate", type=float, required=True, help="Risk-free interest rate (r)."
)
parser.add_argument(
"--price_at_airdrop",
type=float,
required=False,
default=None,
help="Asset price at the time of the airdrop (Pt). Optional, for payoff calculation.",
)
parser.add_argument(
"--tau_s",
type=float,
required=False,
default=None,
help="Stopping Time, when airdrop happens. Optional.",
)
parser.add_argument(
"--simplified",
type=bool,
required=False,
default=True,
help="Use O notation formula, true or false.",
)
args = parser.parse_args()
L = hurdle_rate(args.capital, args.risk_free_rate, args.sigma)
print(f"Hurdle Rate (Li(gamma^-1)): {L:.4f}")
expected_time = expected_exercise_time(
args.initial_price, L, args.mu, args.sigma, args.gamma, args.simplified
)
print(f"Expected Exercise Time (E[T*]): {expected_time:.4f}")
if args.price_at_airdrop is not None and args.tau_s is not None:
payoff_value = payoff(
args.price_at_airdrop, args.capital, args.tau_s, args.risk_free_rate
)
print(f"Payoff: {payoff_value:.4f}")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment