Prechádzať zdrojové kódy

[research/lotterysim] cascade control of block reward value

police 3 rokov pred
rodič
commit
d0aa3de958

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

@@ -1,10 +1,10 @@
 from utils import *
 from utils import *
 
 
 REWARD_MIN = 0
 REWARD_MIN = 0
-REWARD_MAX = 10000
+REWARD_MAX = 1000
 
 
 class RPID:
 class RPID:
-    def __init__(self, kp=0, ki=0, kd=0, dt=1, target_apy=10, Kc=0, Ti=0, Td=0, Ts=0, debug=False):
+    def __init__(self, kp=0, ki=0, kd=0, dt=1, target=80, Kc=0, Ti=0, Td=0, Ts=0, debug=False):
         self.Kp = kp # discrete pid kp
         self.Kp = kp # discrete pid kp
         self.Ki = ki # discrete pid ki
         self.Ki = ki # discrete pid ki
         self.Kd = kd # discrete pid kd
         self.Kd = kd # discrete pid kd
@@ -13,7 +13,7 @@ class RPID:
         self.Td = Td # takahashi td
         self.Td = Td # takahashi td
         self.Ts = Ts # takahashi ts
         self.Ts = Ts # takahashi ts
         self.Kc = Kc # takahashi kc
         self.Kc = Kc # takahashi kc
-        self.target = target_apy # pid set point, target APY
+        self.target = target # pid set point, target
         self.prev_feedback = 0
         self.prev_feedback = 0
         self.feedback_hist = [0, 0]
         self.feedback_hist = [0, 0]
         self.f_hist = [0]
         self.f_hist = [0]

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

@@ -19,3 +19,4 @@ F_MAX_HP = Num(F_MAX)
 EPSILON_HP = Num(EPSILON)
 EPSILON_HP = Num(EPSILON)
 SLOT = 90
 SLOT = 90
 ONE_YEAR = 365.25*24*60*60/SLOT
 ONE_YEAR = 365.25*24*60*60/SLOT
+TARGET_APY = 10

+ 21 - 8
script/research/lotterysim/darkie.py

@@ -16,26 +16,39 @@ class Darkie(Thread):
         self.epoch_len=epoch_len # epoch length during which the stake is static
         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.strategy = strategy if strategy is not None else Strategy(self.epoch_len)
         self.apy_window = apy_window
         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
         self.slot = 0
 
 
     def clone(self):
     def clone(self):
         return Darkie(self.finalized_stake)
         return Darkie(self.finalized_stake)
 
 
     def apy(self):
     def apy(self):
+        '''
         window = 0
         window = 0
         if self.apy_window == 0:
         if self.apy_window == 0:
             window=len(self.initial_stake)
             window=len(self.initial_stake)
         # approximation to APY assuming linear relation
         # approximation to APY assuming linear relation
         # note! relation is logarithmic depending on PID output.
         # note! relation is logarithmic depending on PID output.
+        initial_stake_idx = 0
         if window<len(self.initial_stake):
         if window<len(self.initial_stake):
-            windowed_initial_stake = self.initial_stake[-window]
-            apy =  Num(self.stake - windowed_initial_stake) / Num(windowed_initial_stake) if self.stake>0 else Num(0)
-            #print('slot: {}, windowed apy: {}, gain: {}'.format(self.slot, apy, self.stake-windowed_initial_stake))
-            return apy
-        apy = Num(self.stake - self.initial_stake[0]) / Num(self.initial_stake[0]) if self.stake>0 else Num(0)
-        print('slot: {}, apy: {}, gain: {}'.format(self.slot, apy, self.stake-self.initial_stake[0]))
-        return apy
+            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)
+
+    def staked_tokens(self):
+        '''
+        the ratio of the staked tokens during the epochs
+        of the total running time
+        '''
+        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))
+        assert(staked_ratio <= 100 and staked_ratio >=0)
+        return staked_ratio
 
 
     def apy_percentage(self):
     def apy_percentage(self):
         return self.apy()*100
         return self.apy()*100

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
script/research/lotterysim/f.hist


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

@@ -1 +1 @@
-avg(acc): 0.12014555104338387, avg(apy): 0.3250504347682971, avg(reward): 576.0759327273176, avg(stake ratio): 0.20001903883969724, kp: 0.13499999999919243, ki:5.180999999999765, kd:-0.11000000000000018
+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

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

@@ -7,7 +7,7 @@ os.system("rm f.hist; rm leads.hist")
 
 
 RUNNING_TIME = int(input("running time:"))
 RUNNING_TIME = int(input("running time:"))
 
 
-NODES=10
+NODES=100
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
     darkies = []
     darkies = []
@@ -20,11 +20,11 @@ if __name__ == "__main__":
     for darkie in darkies:
     for darkie in darkies:
         effective_airdrop+=darkie.stake
         effective_airdrop+=darkie.stake
     print("network airdrop: {}, staked token: {}/{}% on {} nodes".format(airdrop, effective_airdrop, effective_airdrop/airdrop*100, len(darkies)))
     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=4.935, r_ki=0.429, r_kd=-0.05)
+    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)
     for darkie in darkies:
     for darkie in darkies:
         dt.add_darkie(darkie)
         dt.add_darkie(darkie)
-    acc = dt.background(rand_running_time=False)
+    acc, avg_apy, avg_reward, stake_ratio = dt.background_with_apy(rand_running_time=False)
     sum_zero_stake = sum([darkie.stake for darkie in darkies[NODES:]])
     sum_zero_stake = sum([darkie.stake for darkie in darkies[NODES:]])
-    print('acc: {}'.format(acc))
+    print('acc: {}, avg(apy): {}, avg(reward): {}, stake_ratio: {}'.format(acc, avg_apy, avg_reward, stake_ratio))
     print('total stake of 0mint: {}, ration: {}'.format(sum_zero_stake, sum_zero_stake/ERC20DRK))
     print('total stake of 0mint: {}, ration: {}'.format(sum_zero_stake, sum_zero_stake/ERC20DRK))
     dt.write()
     dt.write()

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 1
script/research/lotterysim/leads.hist


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

@@ -7,7 +7,7 @@ from pid import PID
 from RPID import RPID
 from RPID import RPID
 
 
 class DarkfiTable:
 class DarkfiTable:
-    def __init__(self, airdrop, running_time, controller_type=CONTROLLER_TYPE_DISCRETE, kp=0, ki=0, kd=0, dt=1, target=1, reward_target=10, kc=0, ti=0, td=0, ts=0, debug=False, r_kp=0, r_ki=0, r_kd=0):
+    def __init__(self, airdrop, running_time, controller_type=CONTROLLER_TYPE_DISCRETE, kp=0, ki=0, kd=0, dt=1, target=1, reward_target=80, kc=0, ti=0, td=0, ts=0, debug=False, r_kp=0, r_ki=0, r_kd=0):
         self.Sigma=airdrop
         self.Sigma=airdrop
         self.darkies = []
         self.darkies = []
         self.running_time=running_time
         self.running_time=running_time
@@ -15,7 +15,7 @@ class DarkfiTable:
         self.end_time=None
         self.end_time=None
         self.pid = None
         self.pid = None
         self.pid = PID(kp=kp, ki=ki, kd=kd, dt=dt, target=target, Kc=kc, Ti=ti, Td=td, Ts=ts)
         self.pid = PID(kp=kp, ki=ki, kd=kd, dt=dt, target=target, Kc=kc, Ti=ti, Td=td, Ts=ts)
-        self.rpid = RPID(kp=r_kp, ki=r_ki, kd=r_kd, target_apy=reward_target)
+        self.rpid = RPID(kp=r_kp, ki=r_ki, kd=r_kd, target=reward_target)
         self.controller_type=controller_type
         self.controller_type=controller_type
         self.debug=debug
         self.debug=debug
 
 
@@ -91,9 +91,10 @@ class DarkfiTable:
                 self.darkies[i].update_stake(rewards[-1])
                 self.darkies[i].update_stake(rewards[-1])
                 ###
                 ###
 
 
-            if count%EPOCH_LENGTH == 0 :
-                acc = self.pid.acc()
-                reward = self.rpid.pid_clipped(float(self.avg_apy()), self.controller_type, debug)
+            if count%EPOCH_LENGTH == 0:
+                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]
                 rewards += [reward]
 
 
             feedback = winners
             feedback = winners
@@ -105,12 +106,17 @@ class DarkfiTable:
             count+=1
             count+=1
         self.end_time=time.time()
         self.end_time=time.time()
         avg_reward = sum(rewards)/len(rewards)
         avg_reward = sum(rewards)/len(rewards)
-        avg_stake_ratio = sum([darkie.strategy.staked_tokens_ratio for darkie in self.darkies])/len(self.darkies)
-        return self.pid.acc(), self.avg_apy()*Num(ONE_YEAR/self.running_time), avg_reward, avg_stake_ratio
+        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):
     def avg_apy(self):
         return sum([darkie.apy_percentage() for darkie in self.darkies])/len(self.darkies)
         return sum([darkie.apy_percentage() 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
+
     def write(self):
     def write(self):
         elapsed=self.end_time-self.start_time
         elapsed=self.end_time-self.start_time
         if self.debug:
         if self.debug:

+ 3 - 0
script/research/lotterysim/pid.py

@@ -116,3 +116,6 @@ class PID:
 
 
     def acc(self):
     def acc(self):
         return sum(np.array(self.feedback_hist)==1)/float(len(self.feedback_hist))
         return sum(np.array(self.feedback_hist)==1)/float(len(self.feedback_hist))
+
+    def acc_percentage(self):
+        return 100*self.acc()

+ 24 - 14
script/research/lotterysim/reward_auto_crawler.py

@@ -4,23 +4,24 @@ from argparse import ArgumentParser
 
 
 AVG_LEN = 5
 AVG_LEN = 5
 
 
-KP_STEP=0.3
-KP_SEARCH=4.935 #-0.91
+KP_STEP=1
+KP_SEARCH=0.01
 
 
-KI_STEP=0.3
-KI_SEARCH=0.429 #157.5
+KI_STEP=1
+KI_SEARCH=-154.52
 
 
-KD_STEP=0.3
-KD_SEARCH=-0.05 #5.6
-
-EPSILON=0.0001
+KD_STEP=1
+KD_SEARCH=-0.5
 
 
 RUNNING_TIME=1000
 RUNNING_TIME=1000
 NODES = 100
 NODES = 100
 
 
+SHIFTING = 0.05
+
+
 highest_apy = 0
 highest_apy = 0
 highest_acc = 0
 highest_acc = 0
-
+highest_staked = 0
 KP='kp'
 KP='kp'
 KI='ki'
 KI='ki'
 KD='kd'
 KD='kd'
@@ -33,8 +34,8 @@ highest_gain = (KP_SEARCH, KI_SEARCH, KD_SEARCH)
 
 
 parser = ArgumentParser()
 parser = ArgumentParser()
 parser.add_argument('-p', '--high-precision', action='store_true')
 parser.add_argument('-p', '--high-precision', action='store_true')
-parser.add_argument('-r', '--randomize-nodes', action='store_false')
-parser.add_argument('-t', '--rand-running-time', action='store_false')
+parser.add_argument('-r', '--randomize-nodes', action='store_true')
+parser.add_argument('-t', '--rand-running-time', action='store_true')
 parser.add_argument('-d', '--debug', action='store_false')
 parser.add_argument('-d', '--debug', action='store_false')
 args = parser.parse_args()
 args = parser.parse_args()
 high_precision = args.high_precision
 high_precision = args.high_precision
@@ -54,6 +55,7 @@ def experiment(apys=[], controller_type=CONTROLLER_TYPE_DISCRETE, rkp=0, rki=0,
 def multi_trial_exp(kp, ki, kd, distribution = [], hp=True):
 def multi_trial_exp(kp, ki, kd, distribution = [], hp=True):
     global highest_apy
     global highest_apy
     global highest_acc
     global highest_acc
+    global highest_staked
     global highest_gain
     global highest_gain
     new_record=False
     new_record=False
     exp_threads = []
     exp_threads = []
@@ -75,16 +77,17 @@ def multi_trial_exp(kp, ki, kd, distribution = [], hp=True):
     if avg_apy > 0:
     if avg_apy > 0:
         gain = (kp, ki, kd)
         gain = (kp, ki, kd)
         acc_gain = (avg_apy, gain)
         acc_gain = (avg_apy, gain)
-        if avg_apy > highest_apy and avg_acc > highest_acc:
+        if avg_staked > highest_staked:
+        #if avg_apy > highest_apy and avg_acc > highest_acc and avg_staked > highest_staked:
             new_record = True
             new_record = True
             highest_apy = avg_apy
             highest_apy = avg_apy
             highest_acc = avg_acc
             highest_acc = avg_acc
+            highest_staked = avg_staked
             highest_gain = (kp, ki, kd)
             highest_gain = (kp, ki, kd)
             with open("highest_gain.txt", 'w') as f:
             with open("highest_gain.txt", 'w') as f:
                 f.write(buff)
                 f.write(buff)
     return buff, new_record
     return buff, new_record
 
 
-SHIFTING = 0.05
 
 
 def crawler(crawl, range_multiplier, step=0.1):
 def crawler(crawl, range_multiplier, step=0.1):
     start = None
     start = None
@@ -103,7 +106,14 @@ def crawler(crawl, range_multiplier, step=0.1):
         range_end += SHIFTING
         range_end += SHIFTING
         step /= 10
         step /= 10
 
 
-    crawl_range = np.arange(range_start, range_end, step)
+
+    while True:
+        try:
+            crawl_range = np.arange(range_start, range_end, step)
+            break
+        except Exception as e:
+            print('start: {}, end: {}, step: {}, exp: {}'.format(range_start, rang_end, step, e))
+            step*=10
     np.random.shuffle(crawl_range)
     np.random.shuffle(crawl_range)
     crawl_range = tqdm(crawl_range)
     crawl_range = tqdm(crawl_range)
     distribution = [random.gauss(ERC20DRK/NODES, ERC20DRK/NODES*0.1) for i in range(NODES)]
     distribution = [random.gauss(ERC20DRK/NODES, ERC20DRK/NODES*0.1) for i in range(NODES)]

+ 11 - 18
script/research/lotterysim/strategy.py

@@ -4,13 +4,15 @@ import math
 class Strategy(object):
 class Strategy(object):
     def __init__(self, epoch_len=0):
     def __init__(self, epoch_len=0):
         self.epoch_len = epoch_len
         self.epoch_len = epoch_len
-        self.staked_tokens_ratio = Num(1)
+        self.staked_tokens_ratio = [Num(1)]
+        self.target_apy = TARGET_APY
 
 
     def set_ratio(self, slot=0, apy=0):
     def set_ratio(self, slot=0, apy=0):
         pass
         pass
 
 
     def staked_value(self, stake):
     def staked_value(self, stake):
-        return self.staked_tokens_ratio*Num(stake)
+        assert(self.staked_tokens_ratio[-1]>=0 and self.staked_tokens_ratio[-1]<=1)
+        return self.staked_tokens_ratio[-1]*Num(stake)
 
 
 class RandomStrategy(Strategy):
 class RandomStrategy(Strategy):
     def __init__(self, epoch_len):
     def __init__(self, epoch_len):
@@ -19,8 +21,7 @@ class RandomStrategy(Strategy):
 
 
     def set_ratio(self, slot, apy=0):
     def set_ratio(self, slot, apy=0):
         if slot%self.epoch_len==0 and slot>EPOCH_LENGTH:
         if slot%self.epoch_len==0 and slot>EPOCH_LENGTH:
-            self.staked_tokens_ratio = random.random()
-            #print('staked ratio: {}'.format(self.staked_tokens_ratio))
+            self.staked_tokens_ratio += [random.random()]
 
 
 class LinearStrategy(Strategy):
 class LinearStrategy(Strategy):
     '''
     '''
@@ -29,12 +30,10 @@ class LinearStrategy(Strategy):
     '''
     '''
     def __init__(self, epoch_len=0):
     def __init__(self, epoch_len=0):
         Strategy.__init__(self, epoch_len)
         Strategy.__init__(self, epoch_len)
-        self.TARGET_APY = 15
 
 
     def set_ratio(self, slot, apy):
     def set_ratio(self, slot, apy):
         if slot%self.epoch_len==0 and slot>EPOCH_LENGTH:
         if slot%self.epoch_len==0 and slot>EPOCH_LENGTH:
-            self.staked_tokens_ratio = apy/Num(self.TARGET_APY)
-            #print('staked ratio: {}'.format(self.staked_tokens_ratio))
+            self.staked_tokens_ratio += [apy/Num(self.target_apy) * Num(0.9) + Num(0.1)]
 
 
 class LogarithmicStrategy(Strategy):
 class LogarithmicStrategy(Strategy):
     '''
     '''
@@ -43,13 +42,12 @@ class LogarithmicStrategy(Strategy):
     '''
     '''
     def __init__(self, epoch_len=0):
     def __init__(self, epoch_len=0):
         Strategy.__init__(self, epoch_len)
         Strategy.__init__(self, epoch_len)
-        self.TARGET_APY = 15
 
 
     def set_ratio(self, slot, apy):
     def set_ratio(self, slot, apy):
         if slot%self.epoch_len==0 and slot>EPOCH_LENGTH:
         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)
-            #print('staked ratio: {}'.format(self.staked_tokens_ratio))
+            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)]
+
 
 
 class SigmoidStrategy(Strategy):
 class SigmoidStrategy(Strategy):
     '''
     '''
@@ -58,13 +56,8 @@ class SigmoidStrategy(Strategy):
     '''
     '''
     def __init__(self, epoch_len=0):
     def __init__(self, epoch_len=0):
         Strategy.__init__(self, epoch_len)
         Strategy.__init__(self, epoch_len)
-        self.TARGET_APY = 10
 
 
     def set_ratio(self, slot, apy):
     def set_ratio(self, slot, apy):
         if slot%self.epoch_len==0 and slot>self.epoch_len:
         if slot%self.epoch_len==0 and slot>self.epoch_len:
-            apy_ratio = math.fabs(apy/self.TARGET_APY)
-            #print("apy ratio: {}".format(apy_ratio))
-            self.staked_tokens_ratio = Num(2/(1+math.pow(math.e, -4*apy_ratio))-1)
-            #print('ratio: {}, staked: {}'.format(apy_ratio, self.staked_tokens_ratio))
-            assert(self.staked_tokens_ratio>=0 and self.staked_tokens_ratio<=1)
-            #print('staked ratio: {}'.format(self.staked_tokens_ratio))
+            apy_ratio = math.fabs(apy/self.target_apy)
+            self.staked_tokens_ratio += [Num(2/(1+math.pow(math.e, -4*apy_ratio))-1)]

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov