diff --git a/.gitignore b/.gitignore index 3c4e94a..f16b75a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ SimCAD.egg-info __pycache__ Pipfile Pipfile.lock -scrapbox/ \ No newline at end of file +scrapbox/ +results/ \ No newline at end of file diff --git a/SimCAD/engine/__init__.py b/SimCAD/engine/__init__.py index 2f61691..c0c5aa2 100644 --- a/SimCAD/engine/__init__.py +++ b/SimCAD/engine/__init__.py @@ -63,8 +63,9 @@ class Executor: # Dimensions: N x r x mechs def single_proc_exec(simulation_execs, states_lists, configs_structs, env_processes_list, Ts, Ns): - simulation, states_list, config = simulation_execs.pop(), states_lists.pop(), configs_structs.pop() - env_processes, T, N = env_processes_list.pop(), Ts.pop(), Ns.pop() + l = [simulation_execs, states_lists, configs_structs, env_processes_list, Ts, Ns] + simulation, states_list, config, env_processes, T, N = list(map(lambda x: x.pop(), l)) + # print(states_list) result = simulation(states_list, config, env_processes, T, N) return flatten(result) diff --git a/SimCAD/engine/simulation.py b/SimCAD/engine/simulation.py index a0a925a..ebb22c6 100644 --- a/SimCAD/engine/simulation.py +++ b/SimCAD/engine/simulation.py @@ -1,6 +1,7 @@ from copy import deepcopy from fn.op import foldr, call - +import pprint +pp = pprint.PrettyPrinter(indent=4) class Executor: def __init__(self, behavior_ops): @@ -61,6 +62,7 @@ class Executor: def block_gen(self, states_list, configs, env_processes, t_step, run): m_step = 0 states_list_copy = deepcopy(states_list) + # print(states_list_copy) # remove copy genesis_states = states_list_copy[-1] genesis_states['mech_step'], genesis_states['time_step'] = m_step, t_step @@ -82,6 +84,7 @@ class Executor: time_seq = [x + 1 for x in time_seq] simulation_list = [states_list] for time_step in time_seq: + # print(run) pipe_run = self.block_gen(simulation_list[-1], configs, env_processes, time_step, run) _, *pipe_run = pipe_run simulation_list.append(pipe_run) @@ -94,9 +97,13 @@ class Executor: pipe_run = [] for run in range(runs): run += 1 - head, *tail = self.pipe(states_list, configs, env_processes, time_seq, run) - head[-1]['mech_step'], head[-1]['time_step'], head[-1]['run'] = 0, 0, run - simulation_list = [head] + tail - pipe_run += simulation_list + # print("Run: "+str(run)) + states_list_copy = deepcopy(states_list) # WHY ??? + head, *tail = self.pipe(states_list_copy, configs, env_processes, time_seq, run) + genesis = head.pop() + genesis['mech_step'], genesis['time_step'], genesis['run'] = 0, 0, run + first_timestep = [genesis] + tail.pop(0) + pipe_run += [first_timestep] + tail + del states_list_copy return pipe_run \ No newline at end of file diff --git a/SimCAD/utils/configuration.py b/SimCAD/utils/configuration.py index e01f4bd..76ba422 100644 --- a/SimCAD/utils/configuration.py +++ b/SimCAD/utils/configuration.py @@ -79,11 +79,6 @@ def sum_dict_values(): # config7c @curried def dict_op(f, d1, d2): - print('d1') - print(d1) - print('d2') - print(d2) - print() def set_base_value(target_dict, source_dict, key): if key not in target_dict: return get_base_value(type(source_dict[key])) diff --git a/sandboxUX/config3.py b/sandboxUX/config3.py index b8b838d..242913d 100644 --- a/sandboxUX/config3.py +++ b/sandboxUX/config3.py @@ -6,7 +6,7 @@ from SimCAD.utils.configuration import exo_update_per_ts, proc_trigger, bound_no ep_time_step seed = { - 'z': np.random.RandomState(1) + 'z': np.random.RandomState(1) } # Signals @@ -19,7 +19,7 @@ external_draw = Decimal('0.01') # between 0 and 1 to draw Buy_Log to external # Stochastic process factors correction_factor = Decimal('0.01') -volatility = Decimal('5.0') +volatility = Decimal('5.0') # Buy_Log_signal = # Z_signal = diff --git a/sandboxUX/config4.py b/sandboxUX/config4.py new file mode 100644 index 0000000..c9243dd --- /dev/null +++ b/sandboxUX/config4.py @@ -0,0 +1,243 @@ +from decimal import Decimal +import numpy as np + +from SimCAD import Configuration, configs +from SimCAD.utils.configuration import exo_update_per_ts, proc_trigger, bound_norm_random, \ + ep_time_step + +seed = { + 'z': np.random.RandomState(1) +} + +# Signals +# Pr_signal +beta = Decimal('0.25') # agent response gain +beta_LT = Decimal('0.1') # LT agent response gain +# alpha = .67, 2 block moving average +alpha = Decimal('0.67') # 21 day EMA forgetfullness between 0 and 1, closer to 1 discounts older obs quicker, should be 2/(N+1) +max_withdraw_factor = Decimal('0.9') +external_draw = Decimal('0.01') # between 0 and 1 to draw Buy_Log to external + + +#alpha * s['Zeus_ST'] + (1 - alpha)*s['Zeus_LT'] + +# Stochastic process factors +correction_factor = Decimal('0.01') +volatility = Decimal('5.0') + +# Buy_Log_signal = +# Z_signal = +# Price_signal = +# TDR_draw_signal = +# P_Ext_Markets_signal = + +# Behaviors per Mechanism + +# BEHAVIOR 1: EMH Trader +EMH_portion = Decimal('0.250') +EMH_Ext_Hold = Decimal('42000.0') + + +def b1m1(step, sL, s): +# print('b1m1') + theta = (s['Z']*EMH_portion*s['Price'])/(s['Z']*EMH_portion*s['Price'] + EMH_Ext_Hold * s['P_Ext_Markets']) + if s['Price'] < (theta*EMH_Ext_Hold * s['P_Ext_Markets'])/(s['Z']*EMH_portion*(1-theta)): + buy = beta * theta*EMH_Ext_Hold * s['P_Ext_Markets']/(s['Price']*EMH_portion*(1-theta)) + return {'buy_order1': buy} + elif s['Price'] > (theta*EMH_Ext_Hold * s['P_Ext_Markets'])/(s['Z']*EMH_portion*(1-theta)): + return {'buy_order1': 0} + else: + return {'buy_order1': 0} + + +def b1m2(step, sL, s): +# print('b1m2') + theta = (s['Z']*EMH_portion*s['Price'])/(s['Z']*EMH_portion*s['Price'] + EMH_Ext_Hold * s['P_Ext_Markets']) + if s['Price'] < (theta*EMH_Ext_Hold * s['P_Ext_Markets'])/(s['Z']*EMH_portion*(1-theta)): + return {'sell_order1': 0} + elif s['Price'] > (theta*EMH_Ext_Hold * s['P_Ext_Markets'])/(s['Z']*EMH_portion*(1-theta)): + sell = beta * theta*EMH_Ext_Hold * s['P_Ext_Markets']/(s['Price']*EMH_portion*(1-theta)) + return {'sell_order1': sell} + else: + return {'sell_order1': 0} + +# BEHAVIOR 3: Herding +Herd_portion = Decimal('0.250') +Herd_Ext_Hold = Decimal('42000.0') +Herd_UB = Decimal('0.10') # UPPER BOUND +Herd_LB = Decimal('0.10') # LOWER BOUND +def b3m2(step, sL, s): + theta = (s['Z']*Herd_portion*s['Price'])/(s['Z']*Herd_portion*s['Price'] + Herd_Ext_Hold * s['P_Ext_Markets']) +# if s['Price'] - s['Price_Signal'] < (theta*Herd_Ext_Hold * s['P_Ext_Markets'])/(s['Z']*Herd_portion*(1-theta)) - Herd_LB: + if (s['Price'] - s['Price_Signal']) < - Herd_LB: + + sell = beta * theta*Herd_Ext_Hold * s['P_Ext_Markets']/(s['Price']*Herd_portion*(1-theta)) + return {'herd_sell': sell, 'herd_buy': 0} + # elif s['Price'] > Herd_UB - (theta*Herd_Ext_Hold * s['P_Ext_Markets'])/(s['Z']*Herd_portion*(1-theta)): + elif (s['Price'] - s['Price_Signal']) > Herd_UB: + buy = beta * theta*Herd_Ext_Hold * s['P_Ext_Markets']/(s['Price']*Herd_portion*(1-theta)) + return {'herd_sell': 0, 'herd_buy': buy} + else: + return {'herd_sell': 0, 'herd_buy': 0} + +# BEHAVIOR 4: HODLers +HODL_belief = Decimal('10.0') +HODL_portion = Decimal('0.250') +HODL_Ext_Hold = Decimal('4200.0') + + +def b4m2(step, sL, s): +# print('b4m2') + theta = (s['Z']*HODL_portion*s['Price'])/(s['Z']*HODL_portion*s['Price'] + HODL_Ext_Hold * s['P_Ext_Markets']) + if s['Price'] < 1/HODL_belief*(theta*HODL_Ext_Hold * s['P_Ext_Markets'])/(s['Z']*HODL_portion*(1-theta)): + sell = beta * theta*HODL_Ext_Hold * s['P_Ext_Markets']/(s['Price']*HODL_portion*(1-theta)) + return {'sell_order2': sell} + elif s['Price'] > (theta*HODL_Ext_Hold * s['P_Ext_Markets'])/(s['Z']*HODL_portion*(1-theta)): + return {'sell_order2': 0} + else: + return {'sell_order2': 0} + + +# STATES +# ZEUS Fixed Supply +def s1m1(step, sL, s, _input): + y = 'Z' + x = s['Z'] #+ _input # / Psignal_int + return (y, x) + + +# def s2m1(step, sL, s, _input): +# y = 'Price' +# x = (s['P_Ext_Markets'] - _input['buy_order1']) / s['Z'] * 10000 +# #x= alpha * s['Z'] + (1 - alpha)*s['Price'] +# return (y, x) + + +def s3m1(step, sL, s, _input): + y = 'Buy_Log' + x = _input['buy_order1'] + _input['herd_buy'] # / Psignal_int + return (y, x) + + +def s4m2(step, sL, s, _input): + y = 'Sell_Log' + x = _input['sell_order1'] + _input['sell_order2'] + _input['herd_sell'] # / Psignal_int + return (y, x) + + +def s3m3(step, sL, s, _input): + y = 'Buy_Log' + x = s['Buy_Log'] + _input # / Psignal_int + return (y, x) + + +# Price Update +def s2m3(step, sL, s, _input): + + y = 'Price' + #var1 = Decimal.from_float(s['Buy_Log']) + x = s['Price'] + s['Buy_Log'] /s['Z'] - s['Sell_Log']/s['Z'] + #+ np.divide(s['Buy_Log'],s['Z']) - np.divide() # / Psignal_int + return (y, x) + +def s5m3(step, sL, s, _input): + y = 'Price_Signal' + x = alpha * s['Price'] + (1 - alpha)*s['Price_Signal'] + return (y, x) + +def s6m1(step, sL, s, _input): + y = 'P_Ext_Markets' + x = s['P_Ext_Markets'] - _input + #x= alpha * s['Z'] + (1 - alpha)*s['Price'] + return (y, x) + + +def s2m2(step, sL, s, _input): + y = 'Price' + x = (s['P_Ext_Markets'] - _input) /s['Z'] *10000 + #x= alpha * s['Z'] + (1 - alpha)*s['Price'] + return (y, x) + +# Exogenous States +proc_one_coef_A = -125 +proc_one_coef_B = 125 + +# A change in belief of actual price, passed onto behaviors to make action +def es4p2(step, sL, s, _input): + y = 'P_Ext_Markets' + x = s['P_Ext_Markets'] + bound_norm_random(seed['z'], proc_one_coef_A, proc_one_coef_B) + + return (y,x) + + +def es5p2(step, sL, s, _input): # accept timedelta instead of timedelta params + y = 'timestamp' + x = ep_time_step(s, s['timestamp'], seconds=1) + return (y, x) + +#Environment States +# NONE + +# Genesis States +state_dict = { + 'Z': Decimal(21000000.0), + 'Price': Decimal(100.0), # Initialize = Z for EMA + 'Buy_Log': Decimal(0.0), + 'Sell_Log': Decimal(0.0), + 'Price_Signal': Decimal(100.0), + 'Trans': Decimal(0.0), + 'P_Ext_Markets': Decimal(25000.0), + 'timestamp': '2018-10-01 15:16:24' +} + +def env_proc_id(x): + return x + +env_processes = {} + +exogenous_states = exo_update_per_ts( + { + "P_Ext_Markets": es4p2, + "timestamp": es5p2 + } +) + +sim_config = { + "N": 20, + "T": range(1000) +} + +# test return vs. non-return functions as lambdas +# test fully defined functions +mechanisms = { + "m1": { + "behaviors": { + "b1": b1m1, + "b3": b3m2 + }, + "states": { + "Z": s1m1, + "Buy_Log": s3m1 + } + }, + "m2": { + "behaviors": { + "b1": b1m2, + "b3": b3m2, + "b4": b4m2 + }, + "states": { + "Sell_Log": s4m2 + } + }, + "m3": { + "behaviors": { + }, + "states": { + "Price": s2m3, + "Price_Signal": s5m3 + } + } +} + +configs.append(Configuration(sim_config, state_dict, seed, exogenous_states, env_processes, mechanisms)) \ No newline at end of file diff --git a/sandboxUX/sim_test.py b/sandboxUX/sim_test.py index 37775c3..5a2dd42 100644 --- a/sandboxUX/sim_test.py +++ b/sandboxUX/sim_test.py @@ -2,8 +2,8 @@ import pandas as pd from tabulate import tabulate from SimCAD.engine import ExecutionMode, ExecutionContext, Executor -# from sandboxUX import config1, config2 -from sandboxUX import config3 +from sandboxUX import config1, config2 +# from sandboxUX import config4 from SimCAD import configs # ToDo: pass ExecutionContext with execution method as ExecutionContext input @@ -18,15 +18,16 @@ single_proc_ctx = ExecutionContext(exec_mode.single_proc) run1 = Executor(single_proc_ctx, single_config) run1_raw_result = run1.main() result = pd.DataFrame(run1_raw_result) +# result.to_csv('~/Projects/DiffyQ-SimCAD/results/config4.csv', sep=',') print(tabulate(result, headers='keys', tablefmt='psql')) print() -# -# print("Simulation Run 2: Pairwise Execution") -# print() -# multi_proc_ctx = ExecutionContext(exec_mode.multi_proc) -# run2 = Executor(multi_proc_ctx, configs) -# run2_raw_results = run2.main() -# for raw_result in run2_raw_results: -# result = pd.DataFrame(raw_result) -# print(tabulate(result, headers='keys', tablefmt='psql')) -# print() \ No newline at end of file + +print("Simulation Run 2: Pairwise Execution") +print() +multi_proc_ctx = ExecutionContext(exec_mode.multi_proc) +run2 = Executor(multi_proc_ctx, configs) +run2_raw_results = run2.main() +for raw_result in run2_raw_results: + result = pd.DataFrame(raw_result) + print(tabulate(result, headers='keys', tablefmt='psql')) +print() \ No newline at end of file