Explorar el Código

[research/lotterysim] fixed a bug in strategy set_ratio override

police hace 3 años
padre
commit
e8d40db440

+ 4 - 4
script/research/lotterysim/reports/acc_vs_staked_ratio.py → script/research/lotterysim/acc_vs_staked_ratio.py

@@ -1,9 +1,9 @@
-from lottery import *
+from core.lottery import *
 import os
 import numpy
 from matplotlib import pyplot as plt
 
-os.system("rm f.hist; rm leads.hist")
+os.system("rm log/f_output.hist; rm log/f_feedback.hist")
 
 RUNNING_TIME = int(input("running time:"))
 ERC20DRK=2.1*10**9
@@ -26,7 +26,7 @@ for portion in range(1,11):
         dt = DarkfiTable(airdrop, RUNNING_TIME, CONTROLLER_TYPE_DISCRETE, kp=0.005999999999989028, ki=-0.005999999985257798, kd=0.01299999999999478)
         for darkie in darkies:
             dt.add_darkie(darkie)
-        acc = dt.background(rand_running_time=False)
+        acc, apy, reward, staked_ratio, apr = dt.background_with_apy(rand_running_time=False)
         accs += [acc]
     avg_acc = sum(accs)/EXPS*100
     plot+=[(stake_portion, avg_acc)]
@@ -35,5 +35,5 @@ for portion in range(1,11):
 plt.plot([x[0] for x in plot], [x[1] for x in plot])
 plt.xlabel('drk staked %')
 plt.ylabel('accuracy %')
-plt.savefig('stake.png')
+plt.savefig('img'+os.sep+'stake.png')
 plt.show()

+ 2 - 2
script/research/lotterysim/core/constants.py

@@ -16,13 +16,13 @@ REWARD_MAX = 1000
 
 SLOT = 90
 ONE_YEAR = 365.25*24*60*60/SLOT
-TARGET_APY = 10
+TARGET_APY = Num(0.5)
 
 PRIMARY_REWARD_TARGET = 70 # ratio of staked tokens
 SECONDARY_LEAD_TARGET = 1 #number of lead per slot
 
 EPSILON = 1
-EPOCH_LENGTH = 50
+EPOCH_LENGTH = 10
 L_HP = Num(L)
 F_MIN_HP = Num(F_MIN)
 F_MAX_HP = Num(F_MAX)

+ 15 - 13
script/research/lotterysim/core/darkie.py

@@ -2,7 +2,7 @@ from core.utils import *
 from core.strategy import *
 
 class Darkie():
-    def __init__(self, airdrop, initial_stake=None, vesting=[], hp=False, commit=True, epoch_len=100, strategy=None, apy_window=EPOCH_LENGTH):
+    def __init__(self, airdrop, initial_stake=None, vesting=[], hp=False, commit=True, epoch_len=EPOCH_LENGTH, strategy=random_strategy(EPOCH_LENGTH)):
         self.vesting = [0] + vesting
         self.stake = (Num(airdrop) if hp else airdrop)
         self.initial_stake = [self.stake] # for debugging purpose
@@ -12,8 +12,7 @@ class Darkie():
         self.f = None
         self.won=False
         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.strategy = strategy
         self.slot = 0
 
     def clone(self):
@@ -28,15 +27,19 @@ class Darkie():
     '''
 
     '''
-    @rewards: array of reward per epoch
+    @rewards: array of reward per epoch, with compound interest.
     '''
-    def apy(self, rewards):
+    def apy_scaled_to_epoch(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]))
+            #print('slot: {}, idx: {} of {}, staked tokens: {}, initial stake: {}'.format(self.slot, 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])
             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
+        #return avg_apy/len(rewards) if len(rewards)>0 else 0
+        return avg_apy
+
+    def apr_scaled_to_runningtime(self):
+        return (self.stake - self.initial_stake[0]) / self.initial_stake[0]
 
     def staked_tokens(self):
         '''
@@ -45,6 +48,7 @@ class Darkie():
         '''
         return Num(self.initial_stake[0])*self.staked_tokens_ratio()
 
+
     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))
@@ -52,8 +56,6 @@ class Darkie():
         assert(staked_ratio <= 100 and staked_ratio >=0)
         return staked_ratio
 
-    def apy_percentage(self, rewards):
-        return Num(self.apy(rewards)*100)
 
     def set_sigma_feedback(self, sigma, feedback, f, count, hp=True):
         self.Sigma = (Num(sigma) if hp else sigma)
@@ -71,10 +73,10 @@ class Darkie():
             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(rewards))
+        if self.slot % EPOCH_LENGTH==0:
+            self.initial_stake +=[self.finalized_stake]
+        self.strategy.set_ratio(self.slot, self.apy_scaled_to_epoch(rewards))
         T = target(self.f, self.strategy.staked_value(self.finalized_stake))
         self.won = lottery(T, hp)
 

+ 12 - 7
script/research/lotterysim/core/lottery.py

@@ -15,7 +15,7 @@ class DarkfiTable:
         self.secondary_pid = SecondaryDiscretePID(kp=kp, ki=ki, kd=kd) if controller_type==CONTROLLER_TYPE_DISCRETE else SecondaryTakahashiPID(kc=kc, ti=ti, td=td, ts=ts)
         self.primary_pid = PrimaryDiscretePID(kp=r_kp, ki=r_ki, kd=r_kd) if controller_type==CONTROLLER_TYPE_DISCRETE else PrimaryTakahashiPID(kc=kc, ti=ti, td=td, ts=ts)
         self.debug=debug
-        self.rewards = [0]
+        self.rewards = []
 
     def add_darkie(self, darkie):
         self.darkies+=[darkie]
@@ -37,6 +37,11 @@ class DarkfiTable:
             total_vesting_stake = 0
             f = self.secondary_pid.pid_clipped(float(feedback), debug)
 
+            if count%EPOCH_LENGTH == 0:
+                acc = self.secondary_pid.acc_percentage()
+                reward = self.primary_pid.pid_clipped(float(self.avg_stake_ratio()), debug)
+                self.rewards += [reward]
+
             #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)
@@ -49,10 +54,6 @@ class DarkfiTable:
                 self.darkies[i].update_stake(self.rewards[-1])
                 ###
 
-            if count%EPOCH_LENGTH == 0 and count > EPOCH_LENGTH:
-                acc = self.secondary_pid.acc_percentage()
-                reward = self.primary_pid.pid_clipped(float(self.avg_stake_ratio()), debug)
-                self.rewards += [reward]
 
             feedback = winners
             if winners==1:
@@ -65,11 +66,15 @@ class DarkfiTable:
         avg_reward = sum(self.rewards)/len(self.rewards)
         stake_ratio = self.avg_stake_ratio()
         avg_apy = self.avg_apy()
+        avg_apr = self.avg_apr()
         #print('apy: {}, staked_ratio: {}'.format(avg_apy, stake_ratio))
-        return self.secondary_pid.acc(), avg_apy, avg_reward, stake_ratio
+        return self.secondary_pid.acc(), avg_apy, avg_reward, stake_ratio, avg_apr
 
     def avg_apy(self):
-        return sum([darkie.apy_percentage(self.rewards) for darkie in self.darkies])/len(self.darkies)
+        return sum([darkie.apy_scaled_to_epoch(self.rewards) for darkie in self.darkies])/len(self.darkies) * Num(ONE_YEAR/self.running_time) * 100
+
+    def avg_apr(self):
+        return sum([darkie.apr_scaled_to_runningtime() for darkie in self.darkies])/len(self.darkies) * (ONE_YEAR/self.running_time) * 100
 
     def avg_stake_ratio(self):
         return sum([darkie.staked_tokens_ratio() for darkie in self.darkies])/len(self.darkies)*100

+ 13 - 13
script/research/lotterysim/core/strategy.py

@@ -8,8 +8,8 @@ class Strategy(object):
         self.target_apy = TARGET_APY
         self.type = 'base'
 
-    def set_ratio(self, slot=0, apy=0):
-        pass
+    def set_ratio(self, slot, apy):
+        return
 
     def staked_value(self, stake):
         #assert(self.staked_tokens_ratio[-1]>=0 and self.staked_tokens_ratio[-1]<=1)
@@ -17,12 +17,11 @@ class Strategy(object):
 
 class RandomStrategy(Strategy):
     def __init__(self, epoch_len):
-        Strategy.__init__(self, epoch_len)
+        super().__init__(epoch_len)
         self.type = 'random'
 
-
-    def set_ratio(self, slot, apy=0):
-        if slot%self.epoch_len==0 and slot>EPOCH_LENGTH:
+    def set_ratio(self, slot, apy):
+        if slot%self.epoch_len==0:
             self.staked_tokens_ratio += [random.random()]
 
 class LinearStrategy(Strategy):
@@ -31,11 +30,11 @@ class LinearStrategy(Strategy):
     assume optimal is 20% APY!
     '''
     def __init__(self, epoch_len=0):
-        Strategy.__init__(self, epoch_len)
+        super().__init__(epoch_len)
         self.type = 'linear'
 
     def set_ratio(self, slot, apy):
-        if slot%self.epoch_len==0 and slot>EPOCH_LENGTH:
+        if slot%self.epoch_len==0:
             self.staked_tokens_ratio += [Num(apy)/Num(self.target_apy)]
 
 class LogarithmicStrategy(Strategy):
@@ -44,11 +43,11 @@ class LogarithmicStrategy(Strategy):
     assume optimal is 20% APY!
     '''
     def __init__(self, epoch_len=0):
-        Strategy.__init__(self, epoch_len)
+        super().__init__(epoch_len)
         self.type = 'logarithmic'
 
     def set_ratio(self, slot, apy):
-        if slot%self.epoch_len==0 and slot>EPOCH_LENGTH:
+        if slot%self.epoch_len==0:
             apy_ratio = math.fabs(apy/self.target_apy)
             fn = lambda x: (math.log(x, 10)+1)/2 * 0.95 + 0.05
             print('apy_ratio: {}, output: {}'.format(apy_ratio, fn(apy_ratio)))
@@ -61,12 +60,13 @@ class SigmoidStrategy(Strategy):
     assume optimal is 20% APY!
     '''
     def __init__(self, epoch_len=0):
-        Strategy.__init__(self, epoch_len)
+        super().__init__(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)
+        if slot%self.epoch_len==0:
+            #TODO should be abs?
+            apy_ratio = apy/self.target_apy
             self.staked_tokens_ratio += [Num(2/(1+math.pow(math.e, -4*apy_ratio))-1)]
 
 

+ 1 - 1
script/research/lotterysim/core/utils.py

@@ -41,4 +41,4 @@ def lottery(T, hp=False, log=False):
         lottery_line = str(y)+","+str(T)+"\n"
         with open("/tmp/sim_lottery_history.log", "a+") as f:
             f.write(lottery_line)
-    return y < T
+    return y < T if y is not None and T is not None else False

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

@@ -13,7 +13,7 @@ if __name__ == "__main__":
     egalitarian = ERC20DRK/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)
+      darkie = Darkie(random.gauss(egalitarian, egalitarian*0.1), strategy=random_strategy(EPOCH_LENGTH))
       darkies += [darkie]
 
     #TODO try rpid with 0mint
@@ -26,8 +26,8 @@ if __name__ == "__main__":
     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)
+    acc, avg_apy, avg_reward, stake_ratio, avg_apr = dt.background_with_apy(rand_running_time=False)
     sum_zero_stake = sum([darkie.stake for darkie in darkies[NODES:]])
-    print('acc: {}, avg(apy): {}, avg(reward): {}, stake_ratio: {}'.format(acc, avg_apy, avg_reward, stake_ratio))
+    print('acc: {}, avg(apy): {}, avg(apr): {}, avg(reward): {}, stake_ratio: {}'.format(acc, avg_apy, avg_apr, avg_reward, stake_ratio))
     print('total stake of 0mint: {}, ration: {}'.format(sum_zero_stake, sum_zero_stake/ERC20DRK))
     dt.write()

BIN
script/research/lotterysim/img/stake.png


+ 1 - 1
script/research/lotterysim/log/f_feedback.hist

@@ -1 +1 @@
-0,0,0.0,1.0,11.0,9.0,11.0,5.0,10.0,100.0,6.0,17.0,
+0,0,0.0,0.0,0.0,0.0,0.0,1.0,2.0,0.0,2.0,100.0,1.0,8.0,100.0,5.0,6.0,100.0,3.0,8.0,100.0,6.0,5.0,100.0,6.0,4.0,100.0,8.0,5.0,100.0,3.0,5.0,100.0,8.0,7.0,100.0,4.0,4.0,100.0,7.0,5.0,100.0,4.0,3.0,100.0,7.0,9.0,100.0,6.0,1.0,100.0,3.0,4.0,100.0,3.0,6.0,100.0,6.0,7.0,100.0,9.0,6.0,100.0,9.0,5.0,100.0,8.0,5.0,100.0,9.0,7.0,100.0,8.0,6.0,100.0,5.0,7.0,100.0,5.0,6.0,100.0,9.0,5.0,100.0,6.0,9.0,100.0,4.0,7.0,100.0,6.0,6.0,100.0,8.0,7.0,100.0,8.0,7.0,100.0,8.0,6.0,100.0,

+ 1 - 1
script/research/lotterysim/log/f_output.hist

@@ -1 +1 @@
-0,0.7290000000000001,0.9999,0.9999,0.9999,0.9999,0.9999,1,0.9999,0.9999,1,
+0,0.7290000000000001,0.6561,0.5904900000000001,0.531441,0.4782969000000001,0.9999,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,0.9999,1,0.9999,

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

@@ -1 +1 @@
-avg(acc): 0.11844586923128297, avg(apy): 1.2942975104128505, avg(reward): 40.70980392156862, avg(stake ratio): 50.98011902568952, kp: 0.2900000000000016, ki:0.4500000000000003, kd:-0.09999999999999953
+avg(acc): 0.140228495669024, avg(apy): 40.57271508914573, avg(reward): 70.0, avg(stake ratio): 50.216539150462765, kp: -0.07000000000000003, ki:-0.3500000000000002, kd:-0.5

+ 2 - 2
script/research/lotterysim/primary_discrete_auto_crawler.py

@@ -50,9 +50,9 @@ def experiment(controller_type=CONTROLLER_TYPE_DISCRETE, rkp=0, rki=0, rkd=0, di
     dt = DarkfiTable(ERC20DRK, RUNNING_TIME, controller_type, kp=-0.010399999999938556, ki=-0.0365999996461878, kd=0.03840000000000491, r_kp=rkp, r_ki=rki, r_kd=rkd)
     RND_NODES = random.randint(5, NODES) if randomize_nodes else NODES
     for idx in range(0,RND_NODES):
-        darkie = Darkie(distribution[idx], strategy=SigmoidStrategy(EPOCH_LENGTH), apy_window=EPOCH_LENGTH)
+        darkie = Darkie(distribution[idx])
         dt.add_darkie(darkie)
-    acc, apy, reward, stake_ratio = dt.background_with_apy(rand_running_time, hp)
+    acc, apy, reward, stake_ratio, apr = dt.background_with_apy(rand_running_time, hp)
     return acc, apy, reward, stake_ratio
 
 def multi_trial_exp(kp, ki, kd, distribution = [], hp=True):

+ 0 - 0
script/research/lotterysim/reports/__init__.py


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

@@ -50,7 +50,7 @@ def experiment(controller_type=CONTROLLER_TYPE_DISCRETE, kp=0, ki=0, kd=0, distr
     for idx in range(0,RND_NODES):
         darkie = Darkie(distribution[idx], strategy=SigmoidStrategy(EPOCH_LENGTH), apy_window=EPOCH_LENGTH)
         dt.add_darkie(darkie)
-    acc, apy, reward, stake_ratio = dt.background_with_apy(rand_running_time, hp)
+    acc, apy, reward, stake_ratio, apr = dt.background_with_apy(rand_running_time, hp)
     return acc
 
 def multi_trial_exp(kp, ki, kd, distribution = [], hp=True):

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

@@ -56,7 +56,7 @@ def experiment(controller_type=CONTROLLER_TYPE_TAKAHASHI, kp=0, ki=0, kd=0, kc=0
     for idx in range(0,RND_NODES):
         darkie = Darkie(distribution[idx], strategy=SigmoidStrategy(EPOCH_LENGTH), apy_window=EPOCH_LENGTH)
         dt.add_darkie(darkie)
-    acc, apy, reward, stake_ratio = dt.background_with_apy(rand_running_time, hp)
+    acc, apy, reward, stake_ratio, apr = dt.background_with_apy(rand_running_time, hp)
     return acc
 
 

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

@@ -13,6 +13,6 @@ if __name__ == "__main__":
     dt  = DarkfiTable(airdrop, RUNNING_TIME, controller_type=CONTROLLER_TYPE_TAKAHASHI, kc=-2.19, ti=-0.5, td=0.25, ts=-0.35,  r_kp=-0.42, r_ki=2.71, r_kd=-0.239)
     for darkie in darkies:
         dt.add_darkie(darkie)
-    acc, apy, reward, stake_ratio = dt.background_with_apy()
+    acc, apy, reward, stake_ratio, apr = dt.background_with_apy()
     print('acc: {}'.format(acc))
     dt.write()