from otree.api import * c = cu doc = '' class C(BaseConstants): NAME_IN_URL = 'EscapingRecessionsGame' PLAYERS_PER_GROUP = None NUM_ROUNDS = 15 PHASE2START = 4 PHASE3START = 11 PITARGET1 = 5 PITARGET2 = 15 PHIPI = 2 GAMMA = 0.3 ALPHA = 0.7 BETA = 1 G = 0 LBAR = 1 D = 0.35 DSHOCK = 0.315 PRICE_SS = 100 NUMPLAYERS = 2 Y_F = 1 DEBT_SS = 36.75 ELB = 0 NOMINT_SS = 0.131 RANGE_SCALAR = 2 POINT_SCALAR = 2 INSTRUCTIONS_TEMPLATE = 'EscapingRecessionsGame/instructions.html' class Subsession(BaseSubsession): pass def group_by_arrival_time_method(subsession: Subsession, waiting_players): if len(waiting_players) >= C.NUMPLAYERS: return waiting_players[:C.NUMPLAYERS] class Group(BaseGroup): median_price_nowcast = models.FloatField() median_price_forecast = models.FloatField() e_nomint_usingmedian = models.FloatField() realized_price = models.FloatField() Total_Consumption_MiddleAged = models.FloatField() Total_Consumption_Young = models.FloatField() Total_Consumption_Old = models.FloatField() Total_Consumption_All = models.FloatField() Actual_Price = models.FloatField() e_net_income = models.FloatField() e_entering_debt = models.FloatField() median_inflation_nowcast = models.FloatField() median_inflation_forecast = models.FloatField() realized_inflation = models.FloatField() rf = models.FloatField() istar = models.FloatField() e_wage = models.FloatField() e_labor = models.FloatField() e_profit = models.FloatField() wage = models.FloatField() realized_labor_provided = models.FloatField() realized_firm_profit = models.FloatField() realized_debt = models.FloatField() realized_wage = models.FloatField() realized_nomint = models.FloatField() realized_output = models.FloatField() wage_flex = models.FloatField() wage_rigid = models.FloatField() def stage1gate(group: Group): import numpy as np round=group.round_number players = group.get_players() """ #turning inflation expectations into price expectations if round == 1: for p in players: p.e_price_today = C.PRICE_SS*(1 + (p.e_pi_today/100)) p.e_price_tomorrow = p.e_price_today*(1 + (p.e_pi_tomorrow/100)) else: for p in players: p.e_price_today = group.in_round(round-1).realized_price*(1 + (p.e_pi_today/100)) p.e_price_tomorrow = p.e_price_today*(1 + (p.e_pi_tomorrow/100)) """ #Getting median price forecasts group.median_price_nowcast = np.median([p.field_maybe_none('e_price_today') for p in players if p.field_maybe_none('e_price_today') is not None]) group.median_price_forecast = np.median([p.field_maybe_none('e_price_tomorrow') for p in players if p.field_maybe_none('e_price_tomorrow') is not None]) #Setting expected inflation: if round==1: group.median_inflation_nowcast = ((group.median_price_nowcast - C.PRICE_SS)/C.PRICE_SS)*100 group.median_inflation_forecast = ((group.median_price_forecast - group.median_price_nowcast)/group.median_price_nowcast)*100 else: group.median_inflation_nowcast = ((group.median_price_nowcast - group.in_round(round-1).realized_price)/group.in_round(round-1).realized_price)*100 group.median_inflation_forecast = ((group.median_price_forecast - group.median_price_nowcast)/group.median_price_nowcast)*100 #Defining rf and istar for entering debt calculations if round <= C.PHASE2START-1: group.rf=((1 + C.BETA) / C.BETA) * (1 + C.G) * (C.D / (C.Y_F - C.D)) - 1 ##calculates the per-period group.istar=((1 + group.rf)*(1+(C.PITARGET1/100)) - 1) elif round==C.PHASE2START: group.rf=((((1 + C.BETA) / C.BETA) * (1 + C.G) * C.DSHOCK )/ (C.Y_F - C.D)) - 1 ##calculates the per-period group.istar=((1 + group.rf)*(1+(C.PITARGET1/100)) - 1) elif round > C.PHASE2START and round < C.PHASE3START: group.rf=((1 + C.BETA) / C.BETA) * (1 + C.G) * (C.DSHOCK / (C.Y_F - C.DSHOCK)) - 1 ##calculates the per-period group.istar=((1 + group.rf)*(1+(C.PITARGET1/100)) - 1) else: group.rf=((1 + C.BETA) / C.BETA) * (1 + C.G) * (C.DSHOCK / (C.Y_F - C.DSHOCK)) - 1 ##calculates the per-period group.istar=((1 + group.rf)*(1+(C.PITARGET2/100)) - 1) ##Expected net income calculation ##First period values using SS values from previous period if round==1: if (group.median_price_nowcast < C.PRICE_SS) : ##If the subjects expect deflation group.e_wage = C.GAMMA*(C.ALPHA*C.PRICE_SS) + (1 - C.GAMMA)*(group.median_price_nowcast * C.ALPHA) group.e_labor = (group.e_wage / (C.ALPHA * group.median_price_nowcast)) ** (1 / (C.ALPHA - 1)) group.e_profit = group.median_price_nowcast * group.e_labor ** C.ALPHA - group.e_wage * group.e_labor group.e_net_income = group.e_wage * group.e_labor + group.e_profit - C.DEBT_SS else: ##else if the subjects expect inflation that is >=0 group.e_net_income = group.median_price_nowcast - C.DEBT_SS ##Need to ensure that the value stored as realized debt in stage2gate includes interest on borrowing else: ##This if condition means subjects expect prices today to be lower than yesterday...i.e. expect deflation if group.median_price_nowcast < group.in_round(round-1).realized_price: group.e_wage = C.GAMMA * group.in_round(round-1).realized_wage + (1 - C.GAMMA) * (group.median_price_nowcast * C.ALPHA) group.e_labor = (group.e_wage / (C.ALPHA * group.median_price_nowcast)) ** (1 / (C.ALPHA - 1)) group.e_profit = group.median_price_nowcast * group.e_labor ** C.ALPHA- group.e_wage * group.e_labor group.e_net_income = (group.e_wage * group.e_labor + group.e_profit - group.in_round(round-1).realized_debt) else:##else...subjects expect inflation group.e_net_income = group.median_price_nowcast - group.in_round(round-1).realized_debt ##Expected nominal interest rate based on median inflation expectations ##This assumes we are increasing the inflation target. If instead we are raising rates, turn this off and turn on negrates option below if round < C.PHASE3START: group.e_nomint_usingmedian = max(1, (1 + group.istar) * ((1+(group.median_inflation_nowcast/100)) / (1+(C.PITARGET1/100))) ** C.PHIPI)-1 else: group.e_nomint_usingmedian = max(1, (1 + group.istar) * ((1+(group.median_inflation_nowcast/100)) / (1+(C.PITARGET2/100))) ** C.PHIPI)-1 """ ##The only difference with the code above is that phase three does not change the inflation target ##but instead changes from a ZLB of 1 to an ELB of 1+ ELB where, for example, an ELB of -.06 creates max(-.06, market clearing rate) ##Notice that I shift the ..-1 to only apply to the second term in the else condition below so that it is more intuitive for us when setting the ELB (for example, we set -.06 instead of .94) if round <= C.PHASE3START: group.e_nomint_usingmedian = max(1, (1 + group.istar) * (group.median_inflation_nowcast / C.PITARGET1) ** C.PHIPI)-1 else: group.e_nomint_usingmedian = max(C.ELB, ((1 + group.istar) * (group.median_inflation_nowcast / C.PITARGET1) ** C.PHIPI)-1)) """ def stage2gate(group: Group): import numpy as np round=group.round_number players = group.get_players() active = sum([1 for p in players if p.IsDropout == False]) ## This gate determines prices, clears markets, etc. ##This code has to account for the change in D (i.e. the shock!) ##before the shock occurs, young households borrow a proportion D of expected middle-aged income if round < C.PHASE2START: #Young borrow D of expected future income, adjusting for the interest they expect to pay #This code accounts for number of young households, which we assume is the same as middle-aged households group.Total_Consumption_Young = active*((C.D*group.median_price_forecast)/( 1+(group.e_nomint_usingmedian) )) else: group.Total_Consumption_Young =active*((C.DSHOCK*group.median_price_forecast)/( 1+(group.e_nomint_usingmedian) )) ##Here, we sum the consumption decisions of all players in a group group.Total_Consumption_MiddleAged = sum([p.consumption_dollars for p in players if p.IsDropout == False]) ##Consumption dollars ought to equal a sum of everything saved by players yesterday ##This code also has to account for initialization in early periods #This assumes old in the first period of play exactly match steady-state equilibrium conditions if round == 1: group.Total_Consumption_Old = active * C.D * group.median_price_nowcast ### starting in round 2, consumption_old is impact by participant decisions. This should depend on what participants did yesterday and possible what happened two periods ago (i.e. before the participants take over) elif round==2: if group.in_round(round-1).realized_price >= C.PRICE_SS: group.Total_Consumption_Old = sum([p.in_round(round-1).realized_savings_dollars for p in players if p.IsDropout == False]) else: for p in players: p.in_round(round-1).realized_savings_dollars =(( (group.in_round(round-1).realized_wage * group.in_round(round-1).realized_labor_provided) + group.in_round(round-1).realized_firm_profit) - p.in_round(round-1).consumption_dollars - ((group.in_round(round-1).Total_Consumption_Young/active) * (1 + C.NOMINT_SS))) * (1 + group.in_round(round-1). realized_nomint) group.Total_Consumption_Old = sum([p.in_round(round-1).realized_savings_dollars for p in players if p.IsDropout==False]) else: if group.in_round(round-1).realized_price >= group.in_round(round-2).realized_price: group.Total_Consumption_Old = sum([p.in_round(round-1).realized_savings_dollars for p in players if p.IsDropout==False]) else: for p in players: p.in_round(round-1).realized_savings_dollars =( (group.in_round(round-1).realized_wage * group.in_round(round-1).realized_labor_provided) + group.in_round(round-1).realized_firm_profit) - p.in_round(round-1).consumption_dollars - ((group.in_round(round-2).Total_Consumption_Young/active) * (1 + group.in_round(round-2).realized_nomint)) * (1 + group.in_round(round-1).realized_nomint) group.Total_Consumption_Old = sum([p.in_round(round-1).realized_savings_dollars for p in players if p.IsDropout==False]) ### Here is the pricing alogorithm epsilon = .00000001 ##This determines how close we must be to zero when solving for prices numerically #Total consumption spending in the current period group.Total_Consumption_All= (group.Total_Consumption_Young + group.Total_Consumption_MiddleAged + group.Total_Consumption_Old)/active ##Exactly matches theory in the appendix D = (1/C.ALPHA)*(group.Total_Consumption_All**((1 - C.ALPHA)/C.ALPHA)) b=(1-C.ALPHA)/C.ALPHA Lbarpwr=C.LBAR**(C.ALPHA-1) A=D*(1-C.GAMMA)*C.ALPHA*Lbarpwr ##If its the first period t=1, then wage_t=0 == C.ALPHA*C.PRICE_SS ##else we use the market clearing wage from the previous period if round==1: B=D*C.GAMMA*(C.ALPHA*C.PRICE_SS) else: B=D*C.GAMMA*group.in_round(round-1).realized_wage ###Starting the N-R method. If period t=1 then we take the equilibrium price from t=0=C.PRICE_SS as our initial guess for prices if round==1: Pguess=C.PRICE_SS pguessb=Pguess**b P=Pguess*(pguessb-A)-B p=(b+1)*pguessb-A #else we use the market clearing price from the previous period else: Pguess=group.in_round(round-1).realized_price pguessb=Pguess**b P=Pguess*(pguessb-A)-B p=(b+1)*pguessb-A while(abs(P)>epsilon): Pguess = Pguess - P/p Pguess=Pguess.real pguessb=Pguess**b P=Pguess*(pguessb-A)-B p=(b+1)*pguessb-A ##The while loop has stopped, which means we have a temporary price that is within our tolerance of epsilon of the root of our implicit price equation group.realized_price=Pguess ## Let's see if this price leads to impossible levels of production PriceCheck=group.Total_Consumption_All/group.realized_price ##If so, the price is too low, let's use the other price rule if(PriceCheck>C.Y_F): group.realized_price=group.Total_Consumption_All/C.Y_F ##Now calculating wages ## Again need to distinguish between rounds 1 and other rounds if round == 1: Wflex=group.realized_price*C.ALPHA*(C.LBAR**(C.ALPHA-1)) group.wage_flex=Wflex Wrigid=C.GAMMA*(C.ALPHA*C.PRICE_SS)+(1-C.GAMMA)*group.realized_price*C.ALPHA*(C.LBAR**(C.ALPHA-1)) group.wage_rigid=Wrigid group.realized_wage=max(Wflex,Wrigid) ##For all other rounds, we use the market-clearing wage from the previous period else: Wflex=group.realized_price*C.ALPHA*(C.LBAR**(C.ALPHA-1)) group.wage_flex=Wflex Wrigid=(C.GAMMA*(group.in_round(round-1).realized_wage))+(1-C.GAMMA)*(group.realized_price*C.ALPHA*(C.LBAR**(C.ALPHA-1))) group.wage_rigid=Wrigid group.realized_wage=max(Wflex,Wrigid) #labor supply group.realized_labor_provided=(group.realized_wage/(group.realized_price*C.ALPHA))**(1/(C.ALPHA-1)) ##Inflation Rates, and again distinguishing between period 1 and other periods # period t=1 then we set inflation as difference between price today and SS price from t=0=C.PRICE_SS if round==1: group.realized_inflation = ((group.realized_price/C.PRICE_SS)-1)*100 #else we use the market clearing prices from today and yesterday else: group.realized_inflation = ((group.realized_price/group.in_round(round-1).realized_price)-1)*100 ##Now determining the interest rate. Here, we will need to distinguish between phases and treatments ###Use this bloc of code for increasing the inflation target: if round < C.PHASE3START: zlb=1 notzlb=(1+group.istar)*((1+(group.realized_inflation/100))/(1+(C.PITARGET1/100)))**C.PHIPI group.realized_nomint = max(zlb,notzlb)-1 else: zlb=1 notzlb=(1+group.istar)*((1+(group.realized_inflation/100))/C.PITARGET2)**C.PHIPI group.realized_nomint = max(zlb,notzlb)-1 ##Use this block of code for allowing negative rates: """ if round < C.PHASE3START: zlb=1 notzlb=(1+group.istar)*((1+(group.realized_inflation/100))/C.PITARGET1)**C.PHIPI group.realized_nomint = max(zlb,notzlb)-1 else: notzlb=(1+group.istar)*((1+(group.realized_inflation/100))/C.PITARGET2)**C.PHIPI group.realized_nomint = max(C.ELB,notzlb-1) """ ##determing how much each player actually has saved for spending tomorrow for p in players: if round==1: p.realized_savings_dollars =(group.realized_price - C.DEBT_SS - p.consumption_dollars)*(1+group.realized_nomint) else: p.realized_savings_dollars =(group.realized_price - group.in_round(round-1).realized_debt - p.consumption_dollars)*(1+group.realized_nomint) #Debt for middle-aged in the next period is what the young spent today multiplied by the nominal interest rate group.realized_debt = (group.Total_Consumption_Young/active)*(1+group.realized_nomint) ##Calculating Output if round == 1: if group.realized_price >= C.PRICE_SS: group.realized_output= active else: group.realized_output= group.Total_Consumption_All/group.realized_price else: if group.realized_price >= group.in_round(round-1).realized_price: group.realized_output= active else: group.realized_output= group.Total_Consumption_All/group.realized_price ##Individual-level firm profit group.realized_firm_profit = group.realized_price*(group.realized_output/active) -group.realized_wage*group.realized_labor_provided ############################################################################################## ############################################################################################## ############################################################################################## #####Now Calculating Consumption Points for this period and forecasting scores for this period ############################################################################################## ############################################################################################## ############################################################################################## ###### Handling the first period seperately if round == 1: #looping through all players -- logic below distinguishes between active and dropouts for p in players: ##Forecasting score ##only need to account for nowcast error in period == 1 #If the player dropped out, we set null values if p.IsDropout == True: p.abs_NE = None p.score_NE = None p.nowcast_range_score = None p.forecast_range_score = None p.units_today_middle = None p.units_today_old = None #If the player is active, we assign real values else: p.abs_NE = abs(p.e_pi_today - group.realized_inflation) p.score_NE = (2**-(p.abs_NE))*C.POINT_SCALAR ##temp var to hold nowcast range that won't be stored in data output nowcast_range = (p.Uncertainty_Upper_N - p.Uncertainty_Lower_N) #If the nowcast range contains realized inflation, the subject earns this if p.Uncertainty_Upper_N+.01 >= group.realized_inflation >= p.Uncertainty_Lower_N-.01: p.nowcast_range_score = C.RANGE_SCALAR/(1+nowcast_range) #If realized inflation is outside the nowcast range, the subject earns nothing else: p.nowcast_range_score = 0 ##In period one, the forecast range score is nothing p.forecast_range_score = 0 #starting the running total of expectations points p.total_expectations_points = p.field_maybe_none('score_NE')+p.field_maybe_none('nowcast_range_score') ##Consumption score #Units consumed by the middle-aged household today p.units_today_middle = p.consumption_dollars/group.realized_price #Units consumed by the old household today p.units_today_old = 0 ##In period one, player only gets consumption points from the middle-aged household #only need to account for consumption today p.consumption_utility_middle = 5.01 + np.log(.0067 + p.units_today_middle) ##starting total consumption points p.total_consumption_points = p.consumption_utility_middle # only consumption points from the middle household ##Else if round > 1 else: for p in players: ##Forecasting score #if the player dropped out, we set null values if p.IsDropout == True: p.abs_NE = None p.score_NE = None p.abs_FE = None p.score_FE = None p.nowcast_range_score = None p.forecast_range_score = None p.units_today_middle = None p.units_today_old = None temp = None p.total_expectations_points = None ## if the player is active, we set actual values else: ###Setting nowcast point and range earnings### #nowcast point# p.abs_NE = abs(p.e_pi_today - group.realized_inflation) p.score_NE = (2**-(p.abs_NE))*C.POINT_SCALAR #nowcast range# #temp var not stored in data output nowcast_range = p.Uncertainty_Upper_N - p.Uncertainty_Lower_N #If realized inflation inside nowcast range if p.Uncertainty_Upper_N+.01 >= group.realized_inflation >= p.Uncertainty_Lower_N-.01: p.nowcast_range_score = C.RANGE_SCALAR/(1+nowcast_range) #if not, player earns nothing else: p.nowcast_range_score = 0 #forecast point# p.abs_FE = abs(p.in_round(round-1).field_maybe_none('e_pi_tomorrow') - group.realized_inflation) p.score_FE = (2**-(p.abs_FE))*C.POINT_SCALAR #forecast range# #forecast tempvar not stored in data output forecast_range = p.in_round(round-1).Uncertainty_Upper_N - p.in_round(round-1).Uncertainty_Lower_N ##If realized inflation (today) lies within the nowcast bounds provided yesterday then subject earns something if p.in_round(round-1).Uncertainty_Upper_F+.01 >= group.realized_inflation >= p.in_round(round-1).Uncertainty_Lower_F -.01: p.forecast_range_score = C.RANGE_SCALAR/(1+forecast_range) #Otherwise, the subject earns nothing else: p.forecast_range_score = 0 #temp holds the point and range forecast earnings for both now cas (nowcast,NE) and forecast (FE, forecast) temp = p.score_NE + p.score_FE + p.nowcast_range_score + p.forecast_range_score # running total of forecast points p.total_expectations_points = temp + p.in_round(round-1).total_expectations_points ##Consumption score #Units consumed by the middle-aged household today p.units_today_middle = p.consumption_dollars/group.realized_price #Units consumed by the old household today p.units_today_old = p.in_round(round-1).realized_savings_dollars/group.realized_price ##In period one, player only gets consumption points from the middle-aged household #consumption from today's middle-aged household p.consumption_utility_middle = 5.01 + np.log(.0067 + p.units_today_middle) #consumption from yesterday's middle-aged household p.consumption_utility_old = 5.01 + np.log(.0067 + p.units_today_old) #storing them both together temp2 = p.consumption_utility_middle + p.consumption_utility_old ##Updating running total of consumption points p.total_consumption_points = temp2 + p.in_round(round-1).total_consumption_points def DropoutsRangeNowcast(group: Group): players = group.get_players() for p in players: if p.IsDropout: p.Uncertainty_Upper_N = p.e_pi_today + .5 p.Uncertainty_Lower_N = p.e_pi_today - .5 else: True def DropoutsRangeForecast(group: Group): players = group.get_players() for p in players: if p.IsDropout: p.Uncertainty_Upper_F = p.e_pi_tomorrow + .5 p.Uncertainty_Lower_F = p.e_pi_tomorrow - .5 else: True def DropoutsBudget(group: Group): import numpy as np players = group.get_players() for p in players: if p.IsDropout: p.consumption_dollars = np.median([p.field_maybe_none('consumption_dollars') for p in players if p.field_maybe_none('consumption_dollars') is not None ]) else: True def flag_update(group: Group): players = group.get_players() round=group.round_number if round > 1: for p in players: p.IsDropout = p.in_round(round-1).IsDropout p.DropOutCheckerFlag = p.in_round(round-1).DropOutCheckerFlag class Player(BasePlayer): e_price_today = models.FloatField(label='Expected price today?', min=0.01) e_price_tomorrow = models.FloatField(label='Expected price tomorrow?', min=0.01) abs_FE = models.FloatField(min=0) score_FE = models.FloatField() abs_NE = models.FloatField(min=0) score_NE = models.FloatField() total_expectations_points = models.FloatField() e_pi_today = models.FloatField(label='Expected inflation today?', min=-100000) e_pi_tomorrow = models.FloatField(label='Expected inflation tomorrow?', min=-100000) consumption_dollars = models.FloatField(initial=0, min=0) e_savings_dollars = models.FloatField() realized_savings_dollars = models.FloatField(min=0) consumption_utility_middle = models.FloatField() consumption_utility_old = models.FloatField() total_consumption_points = models.FloatField() Uncertainty_Upper_N = models.FloatField(label='Nowcast Range - Upper Bound') Uncertainty_Lower_N = models.FloatField(label='Nowcast Range - Lower Bound') Uncertainty_Upper_F = models.FloatField(label='Forecast Range - Upper Bound') Uncertainty_Lower_F = models.FloatField(label='Forecast Range - Lower Bound') IsDropout = models.BooleanField(initial=False) DropOutCheckerFlag = models.BooleanField(choices=[[True, 'No'], [False, 'Yes']], initial=False, label='Are you still participating in the experiment?', widget=widgets.RadioSelectHorizontal) nowcast_range_score = models.FloatField() forecast_range_score = models.FloatField() units_today_middle = models.FloatField() units_today_old = models.FloatField() def Uncertainty_Lower_N_max(player: Player): return player.e_pi_today def Uncertainty_Upper_N_min(player: Player): return player.e_pi_today def Uncertainty_Lower_F_max(player: Player): return player.e_pi_tomorrow def Uncertainty_Upper_F_min(player: Player): return player.e_pi_tomorrow class StartGate(WaitPage): group_by_arrival_time = True body_text = '

Gameplay will begin soon.

' @staticmethod def is_displayed(player: Player): group = player.group current_round=group.round_number if current_round==1: return True else: return False class TimerStart(Page): form_model = 'player' timeout_seconds = 3 @staticmethod def is_displayed(player: Player): group = player.group current_round=group.round_number if current_round==1: return True else: return False class FlagUpdate(WaitPage): after_all_players_arrive = flag_update class ShockAnnouncement(Page): form_model = 'player' timeout_seconds = 10 @staticmethod def is_displayed(player: Player): group = player.group current_round=group.round_number if current_round==C.PHASE2START and player.IsDropout==False: return True else: return False @staticmethod def vars_for_template(player: Player): percent = ((C.DSHOCK - C.D)/C.D)*100 percent = round(percent,2) return dict(percent=percent) class InterventionAnnouncement(Page): form_model = 'player' timeout_seconds = 10 @staticmethod def is_displayed(player: Player): group = player.group current_round=group.round_number if current_round == C.PHASE3START and player.IsDropout==False: return True else: return False @staticmethod def vars_for_template(player: Player): target1= C.PITARGET1 target2 = C.PITARGET2 return dict(target1=target1, target2=target2) class PointForecasts(Page): form_model = 'player' form_fields = ['e_pi_today', 'e_pi_tomorrow'] timeout_seconds = 45 @staticmethod def is_displayed(player: Player): if player.IsDropout: return False else: return True @staticmethod def vars_for_template(player: Player): group = player.group players = group.get_players() current_round=player.round_number round = list(range(1,current_round)) round2 = list(range(1,current_round+2)) price_nowcast = [] price_forecast = [] inflation_nowcast=[] inflation_forecast = [''] realized_inflation=[[-5,5],[-4,5],[-3,5],[-2,5],[-1,5],[0,5]] inflation_target=[[-5,5],[-4,5],[-3,5],[-2,5],[-1,5],[0,5]] realized_prices = [] realized_output = [] period = [] realized_int = [] output_for_display = [] all_values = [p.IsDropout for p in players] if player.IsDropout == False: for r in round: price_nowcast.append(player.in_round(r).field_maybe_none('e_price_today')) price_forecast.append(player.in_round(r).e_price_tomorrow) inflation_nowcast.append(player.in_round(r).e_pi_today) inflation_forecast.append(player.in_round(r).e_pi_tomorrow) realized_prices.append(group.in_round(r).realized_price) realized_inflation.append(group.in_round(r).realized_inflation) period.append(r) realized_int.append(group.in_round(r).realized_nomint*100) realized_output.append(group.in_round(r).realized_output*100) output_for_display.append((group.in_round(r).realized_output*100)/C.NUMPLAYERS) else: True if current_round < C.PHASE3START: for r in round2: inflation_target.append(C.PITARGET1) else: for r in round2: if r < C.PHASE3START: inflation_target.append(C.PITARGET1) else: inflation_target.append(C.PITARGET2) price_nowcast.append('') price_forecast.append('') inflation_nowcast.append('') inflation_forecast.append('') return dict(today=price_nowcast, tomorrow=price_forecast, current_round=current_round,today_pi=inflation_nowcast, tomorrow_pi=inflation_forecast, realized_prices=realized_prices, inflation_target=inflation_target, realized_inflation = realized_inflation, period=period,realized_int=realized_int, realized_output=realized_output,output_for_display=output_for_display, all_values=all_values) @staticmethod def before_next_page(player: Player, timeout_happened): group = player.group round=player.round_number if timeout_happened: player.IsDropout = True player.e_pi_today = None player.e_pi_tomorrow = None player.e_price_today = None player.e_price_tomorrow = None if round == 1 and player.IsDropout == False: player.e_price_today = C.PRICE_SS*(1+ (player.e_pi_today/100)) player.e_price_tomorrow = player.e_price_today*(1+ (player.e_pi_tomorrow/100)) if round > 1 and player.IsDropout == False: player.e_price_today =group.in_round(round-1).realized_price*(1+ (player.e_pi_today/100)) player.e_price_tomorrow = player.e_price_today*(1+ (player.e_pi_tomorrow/100)) @staticmethod def get_timeout_seconds(player: Player): return 45 class ForecastDropoutChecker(Page): form_model = 'player' form_fields = ['DropOutCheckerFlag'] timeout_seconds = 10 @staticmethod def is_displayed(player: Player): if player.IsDropout and player.DropOutCheckerFlag==False: return True else: return False @staticmethod def before_next_page(player: Player, timeout_happened): if timeout_happened: player.IsDropout = True player.DropOutCheckerFlag=True class StillActive(Page): form_model = 'player' timeout_seconds = 10 @staticmethod def is_displayed(player: Player): if player.IsDropout == True and player.DropOutCheckerFlag==False: return True else: return False class InflationForecastSecondTry(Page): form_model = 'player' form_fields = ['e_pi_today', 'e_pi_tomorrow'] timeout_seconds = 30 @staticmethod def is_displayed(player: Player): if player.IsDropout and player.DropOutCheckerFlag==False: return True else: return False @staticmethod def vars_for_template(player: Player): group = player.group current_round=player.round_number round = list(range(1,current_round)) round2 = list(range(1,current_round+2)) price_nowcast = [] price_forecast = [] inflation_nowcast=[] inflation_forecast = [''] realized_inflation=[[-5,5],[-4,5],[-3,5],[-2,5],[-1,5],[0,5]] inflation_target=[[-5,5],[-4,5],[-3,5],[-2,5],[-1,5],[0,5]] realized_prices = [] realized_output = [] period = [] realized_int = [] output_for_display = [] if current_round >1: player.IsDropout=player.in_round(current_round-1).IsDropout if player.IsDropout == False: for r in round: price_nowcast.append(player.in_round(r).field_maybe_none('e_price_today')) price_forecast.append(player.in_round(r).e_price_tomorrow) inflation_nowcast.append(player.in_round(r).e_pi_today) inflation_forecast.append(player.in_round(r).e_pi_tomorrow) realized_prices.append(group.in_round(r).realized_price) realized_inflation.append(group.in_round(r).realized_inflation) period.append(r) realized_int.append(group.in_round(r).realized_nomint*100) realized_output.append(group.in_round(r).realized_output*100) output_for_display.append((group.in_round(r).realized_output*100)/C.NUMPLAYERS) else: True if current_round < C.PHASE3START: for r in round2: inflation_target.append(C.PITARGET1) else: for r in round2: if r < C.PHASE3START: inflation_target.append(C.PITARGET1) else: inflation_target.append(C.PITARGET2) price_nowcast.append('') price_forecast.append('') inflation_nowcast.append('') inflation_forecast.append('') return dict(today=price_nowcast, tomorrow=price_forecast, current_round=current_round,today_pi=inflation_nowcast, tomorrow_pi=inflation_forecast, realized_prices=realized_prices, inflation_target=inflation_target, realized_inflation = realized_inflation, period=period,realized_int=realized_int, realized_output=realized_output,output_for_display=output_for_display ) @staticmethod def before_next_page(player: Player, timeout_happened): group = player.group round=player.round_number player.IsDropout = False player.DropOutCheckerFlag = False if timeout_happened: player.IsDropout = True player.DropOutCheckerFlag = True player.e_pi_today = None player.e_pi_tomorrow = None player.e_price_today = None player.e_price_tomorrow = None if round == 1 and player.IsDropout == False: player.e_price_today = C.PRICE_SS*(1+ (player.e_pi_today/100)) player.e_price_tomorrow = player.e_price_today*(1+ (player.e_pi_tomorrow/100)) if round > 1 and player.IsDropout == False: player.e_price_today =group.in_round(round-1).realized_price*(1+ (player.e_pi_today/100)) player.e_price_tomorrow = player.e_price_today*(1+ (player.e_pi_tomorrow/100)) @staticmethod def get_timeout_seconds(player: Player): return 30 class Stage1Gate(WaitPage): after_all_players_arrive = stage1gate body_text = '

Please wait while all other players make their decisions

' @staticmethod def is_displayed(player: Player): if player.IsDropout == False: return True else: return False class RangeNowcast(Page): form_model = 'player' form_fields = ['Uncertainty_Upper_N', 'Uncertainty_Lower_N'] @staticmethod def is_displayed(player: Player): if player.IsDropout == False: return True else: return False @staticmethod def vars_for_template(player: Player): group = player.group current_round=player.round_number round = list(range(1,current_round)) round2 = list(range(1,current_round+2)) round3 = list(range(1,current_round+1)) price_nowcast = [] price_forecast = [] inflation_nowcast=[] inflation_forecast = [''] realized_prices=[] realized_inflation=[[-5,5],[-4,5],[-3,5],[-2,5],[-1,5],[0,5]] inflation_target=[[-5,5],[-4,5],[-3,5],[-2,5],[-1,5],[0,5]] realized_output = [] period = [] realized_int = [] e_pi_today=player.e_pi_today e_pi_tomorrow=player.e_pi_tomorrow if current_round >1: player.IsDropout=player.in_round(current_round-1).IsDropout for r in round: price_nowcast.append(player.in_round(r).e_price_today) price_forecast.append(player.in_round(r).e_price_tomorrow) realized_prices.append(group.in_round(r).realized_price) realized_inflation.append(group.in_round(r).realized_inflation) period.append(r) realized_int.append(group.in_round(r).realized_nomint*100) realized_output.append(group.in_round(r).realized_output*100) for r in round3: inflation_nowcast.append(player.in_round(r).e_pi_today) inflation_forecast.append(player.in_round(r).e_pi_tomorrow) if current_round < C.PHASE3START: for r in round2: inflation_target.append(C.PITARGET1) else: for r in round2: if r < C.PHASE3START: inflation_target.append(C.PITARGET1) else: inflation_target.append(C.PITARGET2) range_scalar=C.RANGE_SCALAR return dict(today=price_nowcast, tomorrow=price_forecast, current_round=current_round,today_pi=inflation_nowcast, tomorrow_pi=inflation_forecast, realized_prices=realized_prices, inflation_target=inflation_target, realized_inflation = realized_inflation, period=period,realized_int=realized_int, realized_output=realized_output, e_pi_today=e_pi_today,e_pi_tomorrow=e_pi_tomorrow, range_scalar=range_scalar) @staticmethod def before_next_page(player: Player, timeout_happened): if timeout_happened: player.IsDropout = True player.DropOutCheckerFlag = True @staticmethod def get_timeout_seconds(player: Player): current_round=player.round_number if current_round >1: player.IsDropout=player.in_round(current_round-1).IsDropout if player.IsDropout: return 1 else: return 30 class RangeForecast(Page): form_model = 'player' form_fields = ['Uncertainty_Upper_F', 'Uncertainty_Lower_F'] @staticmethod def is_displayed(player: Player): if player.IsDropout == False: return True else: return False @staticmethod def vars_for_template(player: Player): group = player.group current_round=player.round_number round = list(range(1,current_round)) round2 = list(range(1,current_round+2)) round3 = list(range(1,current_round+1)) price_nowcast = [] price_forecast = [] inflation_nowcast=[] inflation_forecast = [''] realized_prices=[] realized_inflation=[[-5,5],[-4,5],[-3,5],[-2,5],[-1,5],[0,5]] inflation_target=[[-5,5],[-4,5],[-3,5],[-2,5],[-1,5],[0,5]] realized_output = [] period = [] realized_int = [] if current_round >1: player.IsDropout=player.in_round(current_round-1).IsDropout e_pi_today=player.e_pi_today e_pi_tomorrow=player.e_pi_tomorrow n_upper = player.Uncertainty_Upper_N n_lower = player.Uncertainty_Lower_N for r in round: price_nowcast.append(player.in_round(r).e_price_today) price_forecast.append(player.in_round(r).e_price_tomorrow) realized_prices.append(group.in_round(r).realized_price) realized_inflation.append(group.in_round(r).realized_inflation) period.append(r) realized_int.append(group.in_round(r).realized_nomint*100) realized_output.append(group.in_round(r).realized_output*100) for r in round3: inflation_nowcast.append(player.in_round(r).e_pi_today) inflation_forecast.append(player.in_round(r).e_pi_tomorrow) if current_round < C.PHASE3START: for r in round2: inflation_target.append(C.PITARGET1) else: for r in round2: if r < C.PHASE3START: inflation_target.append(C.PITARGET1) else: inflation_target.append(C.PITARGET2) range_scalar=C.RANGE_SCALAR return dict(today=price_nowcast, tomorrow=price_forecast, current_round=current_round,today_pi=inflation_nowcast, tomorrow_pi=inflation_forecast, realized_prices=realized_prices, inflation_target=inflation_target, realized_inflation = realized_inflation, period=period,realized_int=realized_int, realized_output=realized_output, e_pi_today=e_pi_today,e_pi_tomorrow=e_pi_tomorrow, n_upper = n_upper, n_lower=n_lower, range_scalar=range_scalar ) @staticmethod def before_next_page(player: Player, timeout_happened): if timeout_happened: player.IsDropout = True player.DropOutCheckerFlag = True @staticmethod def get_timeout_seconds(player: Player): if player.IsDropout: return 1 else: return 30 class Budgeting(Page): form_model = 'player' form_fields = ['consumption_dollars'] @staticmethod def is_displayed(player: Player): if player.IsDropout == False: return True else: return False @staticmethod def vars_for_template(player: Player): group = player.group import random current_round = group.round_number # randomizing slider start position to somewhere within the allowable spending bounds random_value = random.uniform(0, group.e_net_income) rounded_value = round(random_value, 2) nowcast = group.median_inflation_nowcast nowcast = round(nowcast, 2) forecast = group.median_inflation_forecast forecast = round(forecast, 2) price_nowcast = group.median_price_nowcast price_nowcast = round(price_nowcast, 2) price_forecast = group.median_price_forecast price_forecast = round(price_forecast, 2) eni = group.e_net_income eni = round(eni, 2) enomint = (group.e_nomint_usingmedian)*100 enomint = round(enomint,2) ##For debugging period one deflation issues #e_wage = group.field_maybe_none('e_wage') #e_labor = group.field_maybe_none('e_labor') #e_profit = group.field_maybe_none('e_profit') #e_net_income = group.field_maybe_none('e_net_income') return dict(nowcast=nowcast, forecast=forecast, price_nowcast=price_nowcast, price_forecast=price_forecast, eni=eni,enomint=enomint, rounded_value=rounded_value, current_round=current_round) #, e_wage=e_wage, e_labor=e_labor, e_profit=e_profit, e_net_income = e_net_income ) @staticmethod def before_next_page(player: Player, timeout_happened): group = player.group if timeout_happened: player.IsDropout = True ##determing the player-level expected savings based on price expectations and a consumption decision player.e_savings_dollars = (group.e_net_income - player.consumption_dollars)*(1+group.e_nomint_usingmedian) @staticmethod def get_timeout_seconds(player: Player): return 45 class BudgetDropoutChecker(Page): form_model = 'player' form_fields = ['DropOutCheckerFlag'] timeout_seconds = 10 @staticmethod def is_displayed(player: Player): if player.IsDropout and player.DropOutCheckerFlag==False: return True else: return False @staticmethod def before_next_page(player: Player, timeout_happened): if timeout_happened: player.IsDropout = True player.DropOutCheckerFlag=True class BudgetStillActive(Page): form_model = 'player' timeout_seconds = 10 @staticmethod def is_displayed(player: Player): if player.IsDropout == True and player.DropOutCheckerFlag==False: return True else: return False class BudgetSecondChance(Page): form_model = 'player' timeout_seconds = 30 @staticmethod def is_displayed(player: Player): if player.IsDropout and player.DropOutCheckerFlag == False: return True else: return False @staticmethod def vars_for_template(player: Player): group = player.group import random current_round = group.round_number # randomizing slider start position to somewhere within the allowable spending bounds random_value = random.uniform(0, group.e_net_income) rounded_value = round(random_value, 2) nowcast = group.median_inflation_nowcast nowcast = round(nowcast, 2) forecast = group.median_inflation_forecast forecast = round(forecast, 2) price_nowcast = group.median_price_nowcast price_nowcast = round(price_nowcast, 2) price_forecast = group.median_price_forecast price_forecast = round(price_forecast, 2) eni = group.e_net_income eni = round(eni, 2) enomint = (group.e_nomint_usingmedian)*100 enomint = round(enomint,2) ##For debugging period one deflation issues #e_wage = group.field_maybe_none('e_wage') #e_labor = group.field_maybe_none('e_labor') #e_profit = group.field_maybe_none('e_profit') #e_net_income = group.field_maybe_none('e_net_income') return dict(nowcast=nowcast, forecast=forecast, price_nowcast=price_nowcast, price_forecast=price_forecast, eni=eni,enomint=enomint, rounded_value=rounded_value, current_round=current_round) #, e_wage=e_wage, e_labor=e_labor, e_profit=e_profit, e_net_income = e_net_income ) @staticmethod def before_next_page(player: Player, timeout_happened): group = player.group if timeout_happened: player.IsDropout = True player.DropOutCheckerFlag=True else: player.IsDropout = False player.DropOutCheckerFlag = False ##determing the player-level expected savings based on price expectations and a consumption decision player.e_savings_dollars = (group.e_net_income - player.consumption_dollars)*(1+group.e_nomint_usingmedian) class BudgetDropouts(WaitPage): after_all_players_arrive = DropoutsBudget body_text = '

WAITING FOR OTHER PLAYERS TO MAKE DECISIONS

' class Stage2Gate(WaitPage): after_all_players_arrive = stage2gate body_text = '

Please wait while all other players make their decisions

' @staticmethod def is_displayed(player: Player): if player.IsDropout == False and player.DropOutCheckerFlag==False: return True else: return False class Summary(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): if player.IsDropout == False and player.DropOutCheckerFlag==False: return True else: return False @staticmethod def vars_for_template(player: Player): group = player.group #players = group.get_players() current_round = group.round_number consumption_dollars = player.consumption_dollars consumption_dollars = round(consumption_dollars,2 ) young = group.Total_Consumption_Young old = group.Total_Consumption_Old young = round(young,2) old= round(old,2) wage = group.realized_wage wage = round(wage,2) labor = group.realized_labor_provided labor = round(labor,2) profit = group.realized_firm_profit profit = round(profit,2) savings_dollars = player.realized_savings_dollars savings_dollars = round(savings_dollars,2) nomint = group.realized_nomint * 100 nomint = round(nomint,3) price = group.realized_price price = round(price,3) inflation = group.realized_inflation inflation = round(inflation, 2 ) flex=group.wage_flex rigid = group.wage_rigid rounds = list(range(1, current_round + 1)) rounds.reverse() max_round = max(rounds) decisions_data = [ { 'round': i, 'c_middle': round(player.in_round(i).consumption_utility_middle, 2), 'consumption_utility_old': round(player.in_round(i).consumption_utility_old, 2) if i >= 2 else 0, 'forecast': round(player.in_round(i).score_FE, 2) if i >= 2 else 0, 'nowcast': round(player.in_round(i).score_NE, 2), 'forecast_range': round(player.in_round(i).forecast_range_score,2), 'nowcast_range': round(player.in_round(i).field_maybe_none("nowcast_range_score"),2), 'units_middle': round(player.in_round(i).units_today_middle,2), 'units_old': round(player.in_round(i).units_today_old,2), 'interest': round(group.in_round(i).realized_nomint*100,2), 'price': round(group.in_round(i).realized_price, 2), 'inflation': round(group.in_round(i).realized_inflation, 2), 'output': round((group.in_round(i).realized_output*100)/sum([1 for p in group.get_players() if p.in_round(i).IsDropout == False]), 2), 'total_consumption': round(player.in_round(i).total_consumption_points,2), 'total_expectation': round(player.in_round(i).total_expectations_points,2), 'is_first': i == max_round # True if the current item is the first one } for i in rounds ] ####Points variables here #consumption c_middle= player.consumption_utility_middle c_middle=round(c_middle,2) if current_round > 1: c_old = player.consumption_utility_old c_old = round(c_old,2) c_total = player.total_consumption_points c_total = round(c_total,2) #expectations e_nowcast = player.score_NE e_nowcast = round(e_nowcast,2) if current_round > 1: e_forecast = player.score_FE e_forecast = round(e_forecast,2) e_total = player.total_expectations_points e_total = round(e_total,2) if current_round==1: return dict(current_round=current_round, inflation=inflation, consumption_dollars=consumption_dollars, savings_dollars=savings_dollars, price=price, nomint=nomint, young=young, old=old, labor=labor, profit=profit, wage=wage,flex=flex,rigid=rigid, c_middle=c_middle, c_total=c_total, e_nowcast=e_nowcast, e_total=e_total, decisions_data=decisions_data) else: return dict(current_round=current_round, inflation=inflation, consumption_dollars=consumption_dollars, savings_dollars=savings_dollars, price=price, nomint=nomint, young=young, old=old, labor=labor, profit=profit, wage=wage,flex=flex,rigid=rigid, c_middle=c_middle, c_old=c_old, c_total=c_total, e_nowcast=e_nowcast, e_forecast=e_forecast, e_total=e_total, decisions_data=decisions_data) @staticmethod def get_timeout_seconds(player: Player): if player.IsDropout: return 1 else: return 30 page_sequence = [StartGate, TimerStart, FlagUpdate, ShockAnnouncement, InterventionAnnouncement, PointForecasts, ForecastDropoutChecker, StillActive, InflationForecastSecondTry, Stage1Gate, RangeNowcast, RangeForecast, Budgeting, BudgetDropoutChecker, BudgetStillActive, BudgetSecondChance, BudgetDropouts, Stage2Gate, Summary]