Просмотр исходного кода

[research/lotterysim] staking strategies

police 3 лет назад
Родитель
Сommit
ca0545ec44

+ 1 - 1
script/research/lotterysim/constants.py

@@ -7,7 +7,7 @@ CONTROLLER_TYPE_TAKAHASHI=1
 ERC20DRK=2.1*10**9
 
 L = 28948022309329048855892746252171976963363056481941560715954676764349967630337.0
-REWARD = 1
+REWARD = 1000
 F_MIN = 0.0001
 F_MAX = 0.9999
 EPSILON = 1

+ 16 - 13
script/research/lotterysim/darkie.py

@@ -1,19 +1,21 @@
 from utils import *
 from threading import Thread
+from strategy import *
 
 class Darkie(Thread):
-    def __init__(self, airdrop, initial_stake=None, vesting=[], hp=False, commit=True, epoch_len=100):
+    def __init__(self, airdrop, initial_stake=None, vesting=[], hp=False, commit=True, epoch_len=100, strategy=None, apy_window=0):
         Thread.__init__(self)
         self.vesting = [0] + vesting
         self.stake = (Num(airdrop) if hp else airdrop)
-        self.initial_stake = self.stake # for debugging purpose
-        self.finalized_stake = (Num(airdrop) if hp else airdrop) if initial_stake==None else (Num(initial_stake) if hp else initial_stake) # after fork finalization
+        self.initial_stake = [self.stake] # for debugging purpose
+        self.finalized_stake = (Num(airdrop) if hp else airdrop)
         self.Sigma = None
         self.feedback = None
         self.f = None
         self.won=False
-        self.commit = commit # commit to staked tokens
         self.epoch_len=epoch_len # epoch length during which the stake is static
+        self.strategy = strategy if strategy is not None else Strategy(self.epoch_len)
+        self.apy_window = apy_window
         self.staked_tokens_ratio = 1 # ratio of staked tokens, if commit is true then it's 100%
         self.slot = 0
 
@@ -21,9 +23,14 @@ class Darkie(Thread):
         return Darkie(self.finalized_stake)
 
     def apy(self):
+        if self.apy_window == 0:
+            window=len(self.initial_stake)
         # approximation to APY assuming linear relation
         # note! relation is logarithmic depending on PID output.
-        return Num(self.stake - self.initial_stake) / Num(self.initial_stake)
+        if window<len(self.initial_stake):
+            windowed_initial_stake = self.initial_stake[-window]
+            return Num(self.stake - windowed_initial_stake) / Num(windowed_initial_stake)
+        return Num(self.stake - self.initial_stake[0]) / Num(self.initial_stake[0])
 
     def apy_percentage(self):
         return self.apy()*100
@@ -32,15 +39,9 @@ class Darkie(Thread):
         self.Sigma = (Num(sigma) if hp else sigma)
         self.feedback = (Num(feedback) if hp else feedback)
         self.f = (Num(f) if hp else f)
+        self.initial_stake += [self.finalized_stake]
         self.slot = count
 
-    def randomized_finalized_stake(self):
-        if self.commit:
-            return self.finalized_stake
-        if self.slot%self.epoch_len==0:
-            self.staked_tokens_ratio = random.random()
-        return self.staked_tokens_ratio*self.finalized_stake
-
     def run(self, hp=True):
         k=N_TERM
         def target(tune_parameter, stake):
@@ -49,7 +50,9 @@ class Darkie(Thread):
             sigmas = [   c/((self.Sigma+EPSILON)**i) * ( ((L_HP if hp else L)/fact(i)) ) for i in range(1, k+1) ]
             scaled_target = approx_target_in_zk(sigmas, Num(stake)) #+ (BASE_L_HP if hp else BASE_L)
             return scaled_target
-        T = target(self.f, self.randomized_finalized_stake())
+        if self.slot>0:
+            self.strategy.set_ratio(self.slot, self.apy())
+        T = target(self.f, self.strategy.staked_value(self.finalized_stake))
         self.won = lottery(T, hp)
 
     def update_vesting(self):

+ 1 - 0
script/research/lotterysim/f.hist

@@ -0,0 +1 @@
+0,0.7290000000000001,0.7868000003539499,0.6562000014155094,0.47820000212305763,0.4692000017690513,0.6210000014152539,0.6404000017691989,0.5184000024768798,0.4240000024767422,0.500800002476752,0.5094000021228735,0.5844000017690663,0.6124000017691327,0.5740000017691278,0.5740000017691278,0.5826000014152493,0.6490000014153205,0.6020000017691942,0.5442000014152444,0.6490000014153205,0.6020000017691942,0.5270000021230015,0.5076000017690565,0.6210000014152541,0.6404000017691991,0.5442000014152444,0.6404000017691991,0.5442000014152444,0.657600001061442,0.6684000017692655,0.4800000024768751,0.4154000028306209,0.4344000024766809,0.539200002476757,0.5008000024767522,0.5008000024767522,0.5094000021228736,0.5844000017690664,0.6124000017691328,0.5740000017691279,0.556800002476885,0.4326000021228639,0.5844000017690665,0.6124000017691329,0.5826000014152495,0.6404000017691993,0.5356000017691231,0.574000001769128,0.5826000014152495,0.6490000014153208,0.6020000017691944,0.5442000014152446,0.6490000014153208,0.6020000017691944,0.5356000017691231,0.5826000014152495,0.6576000010614422,0.6856000010615086,0.6472000010615038,0.6386000014153823,0.5808000010614325,0.6770000014153872,0.5808000010614325,0.6942000007076301,0.7222000007076965,0.6924000003538131,0.7588000003538844,0.7118000007077581,0.6540000003538082,0.7502000007077629,0.6282000014154439,0.5338000014153063,0.6192000010614376,0.6598000021231445,0.43080000176904726,0.6038000021230118,0.4904000024768141,0.4624000024767478,0.5094000021228742,0.5758000021229455,0.5374000021229406,0.5288000024768191,0.46240000247674784,0.4922000028306313,0.4344000024766814,0.547800002122879,0.5758000021229455,0.546000001769062,0.6124000017691333,0.5740000017691285,0.5826000014152499,0.6404000017691998,0.5356000017691236,0.5740000017691285,0.5826000014152499,0.6232000024769568,0.3942000021228596,0.584400001769067,0.6124000017691335,0.5740000017691286,

+ 1 - 1
script/research/lotterysim/instance.py

@@ -11,7 +11,7 @@ if __name__ == "__main__":
     darkies = []
     egalitarian = ERC20DRK/NODES
     darkies += [ Darkie(random.gauss(egalitarian, egalitarian*0.1)) for id in range(int(NODES)) ]
-    darkies += [Darkie(0) for _ in range(NODES)]
+    #darkies += [Darkie(0) for _ in range(NODES)]
     airdrop = ERC20DRK
     effective_airdrop  = 0
     for darkie in darkies:

+ 1 - 0
script/research/lotterysim/leads.hist

@@ -0,0 +1 @@
+0,0,0,2,4,3,0,0,2,3,1,1,0,0,1,1,1,0,1,2,0,1,2,2,0,0,2,0,2,0,0,3,3,2,0,1,1,1,0,0,1,1,3,0,0,1,0,2,1,1,0,1,2,0,1,2,1,0,0,1,1,2,0,2,0,0,1,0,1,2,0,2,3,1,0,4,0,2,2,1,0,1,1,2,1,2,0,0,1,0,1,1,0,2,1,1,0,4,0,0,1,1,

+ 3 - 3
script/research/lotterysim/stake_reward.py

@@ -1,6 +1,6 @@
 # running time ONE_YEAR
-#network airdrop: 2100000000.0, staked token: 2099223067.1631408/99.9630031982448% on 1000 nodes
-#acc: 37.5249500998004, reward: 0.0005964171059733166794378382704% with instant finality: 0.001589388138790594006649208260%
+#network airdrop: 2100000000.0, staked token: 2099815635.398858/99.99122073327895% on 1000 nodes
+#acc: 35.66458096862327, reward: 0.005966962921188361850310030975% with instant finality: 0.01673078095726943897690808440%
 
 from lottery import *
 import os
@@ -8,7 +8,7 @@ import numpy
 
 os.system("rm f.hist; rm leads.hist")
 
-RUNNING_TIME = ONE_YEAR
+RUNNING_TIME = 1000
 NODES=1000
 
 rewards = []

+ 32 - 0
script/research/lotterysim/strategy.py

@@ -0,0 +1,32 @@
+class Strategy(object):
+    def __init__(self, epoch_len=0):
+        self.epoch_len = epoch_len
+        self.staked_tokens_ratio = 1
+
+    def set_ratio(self, slot=0, apy=0):
+        pass
+
+    def staked_value(self, stake):
+        return self.staked_tokens_ratio*stake
+
+class RandomStrategy(Strategy):
+    def __init__(self, epoch_len):
+        Strategy.__init__(self, epoch_len)
+
+
+    def set_ratio(self, slot, apy=0):
+        if slot%self.epoch_len==0:
+            self.staked_tokens_ratio = random.random()
+
+class LinearStrategy(Strategy):
+    '''
+    linear staking strategy wrt apy.
+    assume optimal is 20% APY!
+    '''
+    def __init__(self, epoch_len=0):
+        Strategy.__init__(self, epoch_len)
+        self.TARGET_APY = 20.0
+
+    def set_ratio(self, slot, apy):
+        if slot%self.epoch_len==0:
+            self.staked_tokens_ratio = apy/self.TARGET_APY