150 lines
5.6 KiB
Python
150 lines
5.6 KiB
Python
import networkx as nx
|
|
from scipy.stats import expon, gamma
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
|
|
#helper functions
|
|
def get_nodes_by_type(g, node_type_selection):
|
|
return [node for node in g.nodes if g.nodes[node]['type']== node_type_selection ]
|
|
|
|
def get_edges_by_type(g, edge_type_selection):
|
|
return [edge for edge in g.edges if g.edges[edge]['type']== edge_type_selection ]
|
|
|
|
def total_funds_given_total_supply(total_supply):
|
|
|
|
#can put any bonding curve invariant here for initializatio!
|
|
total_funds = total_supply
|
|
|
|
return total_funds
|
|
|
|
#maximum share of funds a proposal can take
|
|
default_beta = .2 #later we should set this to be param so we can sweep it
|
|
# tuning param for the trigger function
|
|
default_rho = .001
|
|
|
|
def trigger_threshold(requested, funds, supply, beta = default_beta, rho = default_rho):
|
|
|
|
share = requested/funds
|
|
if share < beta:
|
|
return rho*supply/(beta-share)**2
|
|
else:
|
|
return np.inf
|
|
|
|
def initialize_network(n,m, funds_func=total_funds_given_total_supply, trigger_func =trigger_threshold ):
|
|
network = nx.DiGraph()
|
|
for i in range(n):
|
|
network.add_node(i)
|
|
network.nodes[i]['type']="participant"
|
|
|
|
h_rv = expon.rvs(loc=0.0, scale=1000)
|
|
network.nodes[i]['holdings'] = h_rv
|
|
|
|
s_rv = np.random.rand()
|
|
network.nodes[i]['sentiment'] = s_rv
|
|
|
|
participants = get_nodes_by_type(network, 'participant')
|
|
initial_supply = np.sum([ network.nodes[i]['holdings'] for i in participants])
|
|
|
|
initial_funds = funds_func(initial_supply)
|
|
|
|
#generate initial proposals
|
|
for ind in range(m):
|
|
j = n+ind
|
|
network.add_node(j)
|
|
network.nodes[j]['type']="proposal"
|
|
network.nodes[j]['conviction']=0
|
|
network.nodes[j]['status']='candidate'
|
|
network.nodes[j]['age']=0
|
|
|
|
r_rv = gamma.rvs(3,loc=0.001, scale=10000)
|
|
network.node[j]['funds_requested'] = r_rv
|
|
|
|
network.nodes[j]['trigger']= trigger_threshold(r_rv, initial_funds, initial_supply)
|
|
|
|
for i in range(n):
|
|
network.add_edge(i, j)
|
|
|
|
rv = np.random.rand()
|
|
a_rv = 1-4*(1-rv)*rv #polarized distribution
|
|
network.edges[(i, j)]['affinity'] = a_rv
|
|
network.edges[(i,j)]['tokens'] = 0
|
|
network.edges[(i, j)]['conviction'] = 0
|
|
|
|
proposals = get_nodes_by_type(network, 'proposal')
|
|
total_requested = np.sum([ network.nodes[i]['funds_requested'] for i in proposals])
|
|
|
|
return network, initial_funds, initial_supply, total_requested
|
|
|
|
def trigger_sweep(field, trigger_func,xmax=.2,default_alpha=.5):
|
|
|
|
if field == 'token_supply':
|
|
alpha = default_alpha
|
|
share_of_funds = np.arange(.001,xmax,.001)
|
|
total_supply = np.arange(0,10**9, 10**6)
|
|
demo_data_XY = np.outer(share_of_funds,total_supply)
|
|
|
|
demo_data_Z0=np.empty(demo_data_XY.shape)
|
|
demo_data_Z1=np.empty(demo_data_XY.shape)
|
|
demo_data_Z2=np.empty(demo_data_XY.shape)
|
|
demo_data_Z3=np.empty(demo_data_XY.shape)
|
|
for sof_ind in range(len(share_of_funds)):
|
|
sof = share_of_funds[sof_ind]
|
|
for ts_ind in range(len(total_supply)):
|
|
ts = total_supply[ts_ind]
|
|
tc = ts /(1-alpha)
|
|
trigger = trigger_func(sof, 1, ts)
|
|
demo_data_Z0[sof_ind,ts_ind] = np.log10(trigger)
|
|
demo_data_Z1[sof_ind,ts_ind] = trigger
|
|
demo_data_Z2[sof_ind,ts_ind] = trigger/tc #share of maximum possible conviction
|
|
demo_data_Z3[sof_ind,ts_ind] = np.log10(trigger/tc)
|
|
return {'log10_trigger':demo_data_Z0,
|
|
'trigger':demo_data_Z1,
|
|
'share_of_max_conv': demo_data_Z2,
|
|
'log10_share_of_max_conv':demo_data_Z3,
|
|
'total_supply':total_supply,
|
|
'share_of_funds':share_of_funds}
|
|
elif field == 'alpha':
|
|
alpha = np.arange(.5,1,.01)
|
|
share_of_funds = np.arange(.001,xmax,.001)
|
|
total_supply = 10**9
|
|
demo_data_XY = np.outer(share_of_funds,alpha)
|
|
|
|
demo_data_Z4=np.empty(demo_data_XY.shape)
|
|
demo_data_Z5=np.empty(demo_data_XY.shape)
|
|
demo_data_Z6=np.empty(demo_data_XY.shape)
|
|
demo_data_Z7=np.empty(demo_data_XY.shape)
|
|
for sof_ind in range(len(share_of_funds)):
|
|
sof = share_of_funds[sof_ind]
|
|
for a_ind in range(len(alpha)):
|
|
ts = total_supply
|
|
a = alpha[a_ind]
|
|
tc = ts /(1-a)
|
|
trigger = trigger_func(sof, 1, ts)
|
|
demo_data_Z4[sof_ind,a_ind] = np.log10(trigger)
|
|
demo_data_Z5[sof_ind,a_ind] = trigger
|
|
demo_data_Z6[sof_ind,a_ind] = trigger/tc #share of maximum possible conviction
|
|
demo_data_Z7[sof_ind,a_ind] = np.log10(trigger/tc)
|
|
|
|
return {'log10_trigger':demo_data_Z4,
|
|
'trigger':demo_data_Z5,
|
|
'share_of_max_conv': demo_data_Z6,
|
|
'log10_share_of_max_conv':demo_data_Z7,
|
|
'alpha':alpha,
|
|
'share_of_funds':share_of_funds}
|
|
|
|
else:
|
|
return "invalid field"
|
|
|
|
def trigger_plotter(share_of_funds,Z, color_label,y, ylabel,cmap='jet'):
|
|
dims = (10, 5)
|
|
fig, ax = plt.subplots(figsize=dims)
|
|
|
|
cf = plt.contourf(share_of_funds, y, Z.T, 100, cmap=cmap)
|
|
cbar=plt.colorbar(cf)
|
|
plt.axis([share_of_funds[0], share_of_funds[-1], y[0], y[-1]])
|
|
#ax.set_xscale('log')
|
|
plt.ylabel(ylabel)
|
|
plt.xlabel('Share of Funds Requested')
|
|
plt.title('Trigger Function Map')
|
|
|
|
cbar.ax.set_ylabel(color_label) |