darkie.py 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. from utils import *
  2. from threading import Thread
  3. from strategy import *
  4. class Darkie(Thread):
  5. def __init__(self, airdrop, initial_stake=None, vesting=[], hp=False, commit=True, epoch_len=100, strategy=None, apy_window=0):
  6. Thread.__init__(self)
  7. self.vesting = [0] + vesting
  8. self.stake = (Num(airdrop) if hp else airdrop)
  9. self.initial_stake = [self.stake] # for debugging purpose
  10. self.finalized_stake = (Num(airdrop) if hp else airdrop)
  11. self.Sigma = None
  12. self.feedback = None
  13. self.f = None
  14. self.won=False
  15. self.epoch_len=epoch_len # epoch length during which the stake is static
  16. self.strategy = strategy if strategy is not None else Strategy(self.epoch_len)
  17. self.apy_window = apy_window
  18. self.staked_tokens_ratio = 1 # ratio of staked tokens, if commit is true then it's 100%
  19. self.slot = 0
  20. def clone(self):
  21. return Darkie(self.finalized_stake)
  22. def apy(self):
  23. if self.apy_window == 0:
  24. window=len(self.initial_stake)
  25. # approximation to APY assuming linear relation
  26. # note! relation is logarithmic depending on PID output.
  27. if window<len(self.initial_stake):
  28. windowed_initial_stake = self.initial_stake[-window]
  29. return Num(self.stake - windowed_initial_stake) / Num(windowed_initial_stake) if self.stake>0 else Num(0)
  30. return Num(self.stake - self.initial_stake[0]) / Num(self.initial_stake[0]) if self.stake>0 else Num(0)
  31. def apy_percentage(self):
  32. return self.apy()*100
  33. def set_sigma_feedback(self, sigma, feedback, f, count, hp=True):
  34. self.Sigma = (Num(sigma) if hp else sigma)
  35. self.feedback = (Num(feedback) if hp else feedback)
  36. self.f = (Num(f) if hp else f)
  37. self.initial_stake += [self.finalized_stake]
  38. self.slot = count
  39. def run(self, hp=True):
  40. k=N_TERM
  41. def target(tune_parameter, stake):
  42. x = (Num(1) if hp else 1) - (Num(tune_parameter) if hp else tune_parameter)
  43. c = (x.ln() if type(x)==Num else math.log(x))
  44. sigmas = [ c/((self.Sigma+EPSILON)**i) * ( ((L_HP if hp else L)/fact(i)) ) for i in range(1, k+1) ]
  45. scaled_target = approx_target_in_zk(sigmas, Num(stake)) #+ (BASE_L_HP if hp else BASE_L)
  46. return scaled_target
  47. self.strategy.set_ratio(self.slot, self.apy())
  48. T = target(self.f, self.strategy.staked_value(self.finalized_stake))
  49. self.won = lottery(T, hp)
  50. def update_vesting(self):
  51. if self.slot >= len(self.vesting):
  52. return 0
  53. slot2vest_index = int(self.slot/28800.0)
  54. slot2vest_prev_index = int((self.slot-1)/28800.0)
  55. slot2vest_index_shifted = slot2vest_index - 1 # by end of month
  56. slot2vest_prev_index_shifted = slot2vest_prev_index - 1 # by end of month
  57. vesting_value = float(self.vesting[slot2vest_index_shifted]) - self.vesting[slot2vest_prev_index_shifted]
  58. self.stake+= vesting_value
  59. return vesting_value
  60. def update_stake(self, reward):
  61. if self.won:
  62. self.stake+=reward
  63. def finalize_stake(self):
  64. if self.won:
  65. self.finalized_stake = self.stake
  66. else:
  67. self.stake = self.finalized_stake
  68. def log_state_gain(self):
  69. # darkie started with self.initial_stake, self.initial_stake/self.Sigma percent
  70. # over the course of self.slot
  71. # current stake is self.stake, self.stake/self.Sigma percent
  72. pass