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

[research/lotterysim] fix apy calculation as avg of apy each epoch

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

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

@@ -1,7 +1,7 @@
 from utils import *
 
 REWARD_MIN = 0
-REWARD_MAX = 1000
+REWARD_MAX = 100
 
 class RPID:
     def __init__(self, kp=0, ki=0, kd=0, dt=1, target=80, Kc=0, Ti=0, Td=0, Ts=0, debug=False):

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

@@ -21,22 +21,24 @@ class Darkie(Thread):
     def clone(self):
         return Darkie(self.finalized_stake)
 
+    '''
     def apy(self):
-        '''
-        window = 0
-        if self.apy_window == 0:
-            window=len(self.initial_stake)
-        # approximation to APY assuming linear relation
-        # note! relation is logarithmic depending on PID output.
-        initial_stake_idx = 0
-        if window<len(self.initial_stake):
-            initial_stake_idx = -window
-        '''
-
         staked_tokens = self.staked_tokens()
         apy = (Num(self.stake) - staked_tokens) / staked_tokens if self.stake>0 else 0
         #print('stake: {}, staked_tokens: {}'.format(self.stake, staked_tokens))
         return Num(apy)
+    '''
+
+    '''
+    @rewards: array of reward per epoch
+    '''
+    def apy(self, rewards):
+        avg_apy = 0
+        for idx, reward in enumerate(rewards):
+            #print('idx: {} of {}, staked tokens: {}, initial stake: {}'.format(idx, len(rewards), len(self.strategy.staked_tokens_ratio), len(self.initial_stake)))
+            current_epoch_staked_tokens = (Num(self.strategy.staked_tokens_ratio[idx-1]) * Num(self.initial_stake[idx-1]))
+            avg_apy += (Num(reward) / current_epoch_staked_tokens) if current_epoch_staked_tokens!=0 else 0
+        return avg_apy/len(rewards) if len(rewards)>0 else 0
 
     def staked_tokens(self):
         '''
@@ -47,20 +49,23 @@ class Darkie(Thread):
 
     def staked_tokens_ratio(self):
         staked_ratio = Num(sum(self.strategy.staked_tokens_ratio)/len(self.strategy.staked_tokens_ratio))
+        #print('type: {}, ratio: {}'.format(self.strategy.type, staked_ratio))
+        #TODO (fix)
         assert(staked_ratio <= 100 and staked_ratio >=0)
         return staked_ratio
 
-    def apy_percentage(self):
-        return self.apy()*100
+    def apy_percentage(self, rewards):
+        return self.apy(rewards)*100
 
     def set_sigma_feedback(self, sigma, feedback, f, count, hp=True):
         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.initial_stake += [self.finalized_stake]
         self.slot = count
 
-    def run(self, hp=True):
+
+    def run(self, rewards, hp=True):
         k=N_TERM
         def target(tune_parameter, stake):
             x = (Num(1) if hp else 1)  - (Num(tune_parameter) if hp else tune_parameter)
@@ -68,11 +73,14 @@ 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
+        if self.slot % EPOCH_LENGTH==0  and self.slot > EPOCH_LENGTH:
+            self.initial_stake +=[self.finalized_stake]
 
-        self.strategy.set_ratio(self.slot, self.apy_percentage())
+        self.strategy.set_ratio(self.slot, self.apy_percentage(rewards))
         T = target(self.f, self.strategy.staked_value(self.finalized_stake))
         self.won = lottery(T, hp)
 
+
     def update_vesting(self):
         if self.slot >= len(self.vesting):
             return 0

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
script/research/lotterysim/f.hist


+ 1 - 1
script/research/lotterysim/highest_gain.txt

@@ -1 +1 @@
-avg(acc): 0.35748502994011977, avg(apy): 8.118964857253877, avg(reward): 945.6876526591744, avg(stake ratio): 92.50646258907183, kp: -0.08000000000000003, ki:-154.52, kd:-0.5
+avg(acc): 0.33812375249501, avg(apy): 1.6658332654209573, avg(reward): 710.959757565603, avg(stake ratio): 60.78435509175097, kp: -0.42000000000000043, ki:2.7100000000000035, kd:-0.23999999999999488

+ 6 - 2
script/research/lotterysim/instance.py

@@ -12,7 +12,11 @@ NODES=100
 if __name__ == "__main__":
     darkies = []
     egalitarian = ERC20DRK/NODES
-    darkies += [ Darkie(random.gauss(egalitarian, egalitarian*0.1), strategy=SigmoidStrategy(EPOCH_LENGTH), apy_window=EPOCH_LENGTH) for id in range(int(NODES)) ]
+    darkies = []
+    for id in range(int(NODES)):
+      darkie = Darkie(random.gauss(egalitarian, egalitarian*0.1), strategy=random_strategy(EPOCH_LENGTH), apy_window=EPOCH_LENGTH)
+      darkies += [darkie]
+
     #TODO try rpid with 0mint
     #darkies += [Darkie(0, strategy=LinearStrategy(EPOCH_LENGTH)) for _ in range(NODES)]
     airdrop = ERC20DRK
@@ -20,7 +24,7 @@ if __name__ == "__main__":
     for darkie in darkies:
         effective_airdrop+=darkie.stake
     print("network airdrop: {}, staked token: {}/{}% on {} nodes".format(airdrop, effective_airdrop, effective_airdrop/airdrop*100, len(darkies)))
-    dt = DarkfiTable(airdrop, RUNNING_TIME, CONTROLLER_TYPE_DISCRETE, kp=-0.010399999999938556, ki=-0.0365999996461878, kd=0.03840000000000491,  r_kp=0.01, r_ki=-154.52, r_kd=-0.504)
+    dt = DarkfiTable(airdrop, RUNNING_TIME, CONTROLLER_TYPE_DISCRETE, kp=-0.010399999999938556, ki=-0.0365999996461878, kd=0.03840000000000491,  r_kp=-0.42, r_ki=2.71, r_kd=-0.239)
     for darkie in darkies:
         dt.add_darkie(darkie)
     acc, avg_apy, avg_reward, stake_ratio = dt.background_with_apy(rand_running_time=False)

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
script/research/lotterysim/leads.hist


+ 12 - 13
script/research/lotterysim/lottery.py

@@ -18,6 +18,7 @@ class DarkfiTable:
         self.rpid = RPID(kp=r_kp, ki=r_ki, kd=r_kd, target=reward_target)
         self.controller_type=controller_type
         self.debug=debug
+        self.rewards = [0]
 
     def add_darkie(self, darkie):
         self.darkies+=[darkie]
@@ -33,7 +34,6 @@ class DarkfiTable:
         #if rand_running_time and debug:
             #print("random running time: {}".format(self.running_time))
             #print('running time: {}'.format(self.running_time))
-        rewards = [0]
         while count < self.running_time:
             winners=0
             total_vesting_stake = 0
@@ -41,17 +41,17 @@ class DarkfiTable:
             #note! thread overhead is 10X slower than sequential node execution!
             for i in range(len(self.darkies)):
                 self.darkies[i].set_sigma_feedback(self.Sigma, feedback, f, count, hp)
-                self.darkies[i].run(hp)
+                self.darkies[i].run(self.rewards, hp)
                 total_vesting_stake+=self.darkies[i].update_vesting()
             for i in range(len(self.darkies)):
                 winners += self.darkies[i].won
-                print('reward: {}'.format(rewards[-1]))
-                self.darkies[i].update_stake(rewards[-1])
+                print('reward: {}'.format(self.rewards[-1]))
+                self.darkies[i].update_stake(self.rewards[-1])
 
             if count%EPOCH_LENGTH == 0:
                 acc = self.pid.acc()
                 reward = self.rpid.pid_clipped(float(self.avg_apy()), self.controller_type, debug)
-                rewards += [reward]
+                self.rewards += [reward]
             feedback = winners
             if winners==1:
                 if count >= ERC20DRK:
@@ -73,7 +73,7 @@ class DarkfiTable:
         #if rand_running_time and debug:
             #print("random running time: {}".format(self.running_time))
             #print('running time: {}'.format(self.running_time))
-        rewards = [0]
+
         while count < self.running_time:
             winners=0
             total_vesting_stake = 0
@@ -82,20 +82,19 @@ class DarkfiTable:
             #note! thread overhead is 10X slower than sequential node execution!
             for i in range(len(self.darkies)):
                 self.darkies[i].set_sigma_feedback(self.Sigma, feedback, f, count, hp)
-                self.darkies[i].run(hp)
+                self.darkies[i].run(self.rewards, hp)
                 total_vesting_stake+=self.darkies[i].update_vesting()
 
             #print('reward: {}'.format(rewards[-1]))
             for i in range(len(self.darkies)):
                 winners += self.darkies[i].won
-                self.darkies[i].update_stake(rewards[-1])
+                self.darkies[i].update_stake(self.rewards[-1])
                 ###
 
-            if count%EPOCH_LENGTH == 0:
+            if count%EPOCH_LENGTH == 0 and count > EPOCH_LENGTH:
                 acc = self.pid.acc_percentage()
                 reward = self.rpid.pid_clipped(float(self.avg_stake_ratio()), self.controller_type, debug)
-                #print('reward: {}'.format(reward))
-                rewards += [reward]
+                self.rewards += [reward]
 
             feedback = winners
             if winners==1:
@@ -105,14 +104,14 @@ class DarkfiTable:
                     self.darkies[i].finalize_stake()
             count+=1
         self.end_time=time.time()
-        avg_reward = sum(rewards)/len(rewards)
+        avg_reward = sum(self.rewards)/len(self.rewards)
         stake_ratio = self.avg_stake_ratio()
         avg_apy = self.avg_apy()
         #print('apy: {}, staked_ratio: {}'.format(avg_apy, stake_ratio))
         return self.pid.acc(), avg_apy, avg_reward, stake_ratio
 
     def avg_apy(self):
-        return sum([darkie.apy_percentage() for darkie in self.darkies])/len(self.darkies)
+        return sum([darkie.apy_percentage(self.rewards) for darkie in self.darkies])/len(self.darkies)
 
     def avg_stake_ratio(self):
         return sum([darkie.staked_tokens_ratio() for darkie in self.darkies])/len(self.darkies)*100

+ 3 - 4
script/research/lotterysim/reward_auto_crawler.py

@@ -8,7 +8,7 @@ KP_STEP=1
 KP_SEARCH=0.01
 
 KI_STEP=1
-KI_SEARCH=-154.52
+KI_SEARCH=1#-154.52
 
 KD_STEP=1
 KD_SEARCH=-0.5
@@ -18,7 +18,6 @@ NODES = 100
 
 SHIFTING = 0.05
 
-
 highest_apy = 0
 highest_acc = 0
 highest_staked = 0
@@ -77,7 +76,7 @@ def multi_trial_exp(kp, ki, kd, distribution = [], hp=True):
     if avg_apy > 0:
         gain = (kp, ki, kd)
         acc_gain = (avg_apy, gain)
-        if avg_staked > highest_staked:
+        if avg_acc > highest_acc:
         #if avg_apy > highest_apy and avg_acc > highest_acc and avg_staked > highest_staked:
             new_record = True
             highest_apy = avg_apy
@@ -122,7 +121,7 @@ def crawler(crawl, range_multiplier, step=0.1):
         ki = i if crawl==KI else highest_gain[1]
         kd = i if crawl==KD else highest_gain[2]
         buff, new_record = multi_trial_exp(kp, ki, kd, distribution, hp=high_precision)
-        crawl_range.set_description('highest:{} / {}'.format(highest_apy, buff))
+        crawl_range.set_description('highest:{} / {}'.format(highest_acc, buff))
         if new_record:
             break
 

+ 22 - 5
script/research/lotterysim/strategy.py

@@ -4,19 +4,21 @@ import math
 class Strategy(object):
     def __init__(self, epoch_len=0):
         self.epoch_len = epoch_len
-        self.staked_tokens_ratio = [Num(1)]
+        self.staked_tokens_ratio = [1]
         self.target_apy = TARGET_APY
+        self.type = 'base'
 
     def set_ratio(self, slot=0, apy=0):
         pass
 
     def staked_value(self, stake):
-        assert(self.staked_tokens_ratio[-1]>=0 and self.staked_tokens_ratio[-1]<=1)
-        return self.staked_tokens_ratio[-1]*Num(stake)
+        #assert(self.staked_tokens_ratio[-1]>=0 and self.staked_tokens_ratio[-1]<=1)
+        return Num(self.staked_tokens_ratio[-1])*Num(stake)
 
 class RandomStrategy(Strategy):
     def __init__(self, epoch_len):
         Strategy.__init__(self, epoch_len)
+        self.type = 'random'
 
 
     def set_ratio(self, slot, apy=0):
@@ -30,10 +32,11 @@ class LinearStrategy(Strategy):
     '''
     def __init__(self, epoch_len=0):
         Strategy.__init__(self, epoch_len)
+        self.type = 'linear'
 
     def set_ratio(self, slot, apy):
         if slot%self.epoch_len==0 and slot>EPOCH_LENGTH:
-            self.staked_tokens_ratio += [apy/Num(self.target_apy) * Num(0.9) + Num(0.1)]
+            self.staked_tokens_ratio += [Num(apy)/Num(self.target_apy)]
 
 class LogarithmicStrategy(Strategy):
     '''
@@ -42,11 +45,14 @@ class LogarithmicStrategy(Strategy):
     '''
     def __init__(self, epoch_len=0):
         Strategy.__init__(self, epoch_len)
+        self.type = 'logarithmic'
 
     def set_ratio(self, slot, apy):
         if slot%self.epoch_len==0 and slot>EPOCH_LENGTH:
             apy_ratio = math.fabs(apy/self.target_apy)
-            self.staked_tokens_ratio += [Num((math.log(apy_ratio, 10)+1)/2 if apy_ratio != 0 else 0)]
+            fn = lambda x: (math.log(x, 10)+1)/2 * 0.95 + 0.05
+            print('apy_ratio: {}, output: {}'.format(apy_ratio, fn(apy_ratio)))
+            self.staked_tokens_ratio += [Num(fn(apy_ratio) if apy_ratio != 0 else 0)]
 
 
 class SigmoidStrategy(Strategy):
@@ -56,8 +62,19 @@ class SigmoidStrategy(Strategy):
     '''
     def __init__(self, epoch_len=0):
         Strategy.__init__(self, epoch_len)
+        self.type = 'sigmoid'
 
     def set_ratio(self, slot, apy):
         if slot%self.epoch_len==0 and slot>self.epoch_len:
             apy_ratio = math.fabs(apy/self.target_apy)
             self.staked_tokens_ratio += [Num(2/(1+math.pow(math.e, -4*apy_ratio))-1)]
+
+
+def random_strategy(epoch_length):
+    rnd = random.random()
+    if rnd < 0.25:
+        return RandomStrategy(epoch_length)
+    elif rnd < 0.5 and rnd >=0.25:
+        return LinearStrategy(epoch_length)
+    else:
+        return SigmoidStrategy(epoch_length)

Некоторые файлы не были показаны из-за большого количества измененных файлов