Skip to content

Instantly share code, notes, and snippets.

@t1nak
Created October 5, 2017 20:31
Show Gist options
  • Save t1nak/87e6327d82c51dea4ef6eed2178e1546 to your computer and use it in GitHub Desktop.
Save t1nak/87e6327d82c51dea4ef6eed2178e1546 to your computer and use it in GitHub Desktop.
toy model python
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Explanation of python code\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"Dear Yordan, \n",
"\n",
"Kindly find attached a folder containing python code for the toy model in the stock flow presentation. The coding of system wide stress simulation is part of my deliverables. In addition, I thought it may be useful for you to have an object orientated programming framework in python because it is associated with agent based modelling. In object-oriented programming languages, data and programming methods or functions are “embedded” in objects that can manipulate their own data and interact with other programming objects. This makes real-world entities such as households or banks easy to be represented. For example, in this model a natural starting point is to define an object/class called “Dealer banks”. I specified information dealers would need to have and rules for how they interact with each other and their environment. Another feature of object-oriented programming that is good for ABM development is inheritance. An instantiated object, e.g. commercial bank, can ‘inherit’ some characteristics from a ‘parent class’ but still behave in different ways. \n",
"\n",
"However, the obvious downside is that Python coding is definitely harder than Matlab. For example, there is no interface to click on a variable set(not that I\"m aware of anyway), you have to save the variables in a dataframe (by writing a function in the code) and then write the dataframe to a csv file. On the upside, it’s possible to automate the update state easily and add heterogenous behavior for same-type like institutions. Another feature is that \n",
"\n",
"\n",
"\n",
"## How to run the model\n",
"\n",
"Running python :\n",
" For python code to be executed the computer needs \n",
" to have python 2 or python 3 installed (via https://www.python.org) \n",
" A nice coding editor like Sublime Text 3, Atom or pycharm. The good thing about pycharm is that you can run the \n",
" code in the editor without installing additional packages. On my mac, I actually run the code in the terminal \n",
" (also called bash). I think in Windows, the equivalent is the shell. The program is run via command line codes. So \n",
" I go to the path of where the folders are stored and type.\n",
" \n",
" \n",
" \n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" ```ruby \n",
"python sflow.py```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Alternatively, for example in pycharm, you can open the slfow.py program and then run it. \n",
"This executes the whole program and writes a csv file with the output in the main folder ```stockflow```. \n",
"If you want to change things in this model, the main files you will be working on are the agent scripts \n",
"in src/institution, the updater.py and the configuration files in /configs/. \n",
"\n",
"So let's start by looking at the main file: \n",
"## Sflow.py"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"***In t=: 0 This is the price matrix***\n",
"[['t' 'pGB' 'pCB']\n",
" ['0.0' '1.0' '1.0']] \n",
"1.**** UPDATER.PY*** FIRST INITIALIZE ASSETS\n",
"***********\n",
"HF Assets: \n",
"\n",
"Cash: 10.0 \n",
"\n",
"GB: 40.0 \n",
"\n",
"CB: 58.0 \n",
"\n",
"Total: 108.0 \n",
"\n",
"Liabilities: \n",
"\n",
"Repo 38.0 \n",
"\n",
"Investment shares: 70.0 \n",
"\n",
"2.**** UPDATER.PY*** Now calculate profit and loss\n",
"******* The HF has profit in t= 0 of 2.36\n",
"******* The PF has profit in t= 0 of 2.2\n",
"******* The IC has profit in t= 0 of 3.6\n",
"******* The IF Investment fund has profit in t= 0 of 2.7\n",
"******* The cbank has profit in t= 0 of -0.06\n",
"******* The dealer has profit in t= 0 of 1.3\n",
"******* The MMF has profit in t= 0 of 1.425\n",
"***\n",
"This run had 1 sweeps and 5.0 simulations\n",
"***In t=: 0 This is the price matrix***\n",
"[['t' 'pGB' 'pCB']\n",
" ['0.0' '1.0' '1.0']] \n",
"1.**** UPDATER.PY*** FIRST INITIALIZE ASSETS\n",
"***********\n",
"HF Assets: \n",
"\n",
"Cash: 10.0 \n",
"\n",
"GB: 40.0 \n",
"\n",
"CB: 58.0 \n",
"\n",
"Total: 108.0 \n",
"\n",
"Liabilities: \n",
"\n",
"Repo 38.0 \n",
"\n",
"Investment shares: 70.0 \n",
"\n",
"2.**** UPDATER.PY*** Now calculate profit and loss\n",
"******* The HF has profit in t= 0 of 2.36\n",
"******* The PF has profit in t= 0 of 2.2\n",
"******* The IC has profit in t= 0 of 3.6\n",
"******* The IF Investment fund has profit in t= 0 of 2.7\n",
"******* The cbank has profit in t= 0 of -0.06\n",
"******* The dealer has profit in t= 0 of 1.3\n",
"******* The MMF has profit in t= 0 of 1.425\n",
"***\n",
"This run had 1 sweeps and 5.0 simulations\n",
]
}
],
"source": [
"# %load sflow.py\n",
"# [SublimeLinter pep8-max-line-length:300]\n",
"# -*- coding: utf-8 -*-\n",
"\n",
"# -------------------------------------------------------------------------\n",
"#\n",
"# MAIN\n",
"#\n",
"# -------------------------------------------------------------------------\n",
"if __name__ == '__main__':\n",
"\n",
" from src.environment import Environment\n",
" from src.runner import Runner\n",
"\n",
"# We have to pass in the path of the environment xml as args[0] \n",
"# the name of the environment xml as args[1] here:\n",
"# and the scenario name as args[2] here:\n",
"\n",
" args = [\"configs/environment/\", \"environment_config\", \"benchmark\"]\n",
"\n",
"#\n",
"# INITIALIZATION\n",
"#\n",
" environment_directory = str(args[0])\n",
" identifier = str(args[1])\n",
" scenario = str(args[2])\n",
" environment = Environment(environment_directory, identifier)\n",
" runner = Runner(environment, scenario)\n",
"\n",
"#\n",
"# UPDATE STEP\n",
"#\n",
" for i in range(int(environment.static_parameters['num_simulations'])):\n",
" environment.initialize(environment_directory, identifier)\n",
" runner.initialize(environment, scenario)\n",
" # do the run\n",
" runner.do_run(environment, scenario)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the beginning we need to instantiate two objects in the main file to run the program -\n",
"\n",
"``` from src.environment import Environment\n",
" from src.runner import Runner```\n",
"\n",
"\n",
"\n",
"the Environment and the Runner class. The code for those classes are stored in the folder src and the name of the classes are Environment and Runner (not surprising).\n",
"* The runner has two main purposes - it just handles the time steps and writes the output to csv. \n",
"* The environment has the purpose of reading all the configuration files, instantiating the agents and saving the agents in lists to access them in the actual modelling part. So whenever you want to access a variable for an agent in the updater (for example a cash position of a hedgefund), you need to write \n",
"\n",
"```ruby \n",
"for hr in environment.hedgefunds:\n",
" print hr.Cash```\n",
" \n",
"The instantiation of the agents takes up quite a bit of code in the environment file. The code reads the data for the agents from configuration files you find in /configs. A configuration file for the agents is stored in an agent folder because python iterates through the folder to look for all config files for a specific agent. It's possible to store them all in one place but then the automation code of the instantiation has to be changed. \n",
"An agent config file looks like this: \n",
" "
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"ename": "SyntaxError",
"evalue": "invalid syntax (<ipython-input-4-afb99b5d9553>, line 2)",
"output_type": "error",
"traceback": [
"\u001b[0;36m File \u001b[0;32m\"<ipython-input-4-afb99b5d9553>\"\u001b[0;36m, line \u001b[0;32m2\u001b[0m\n\u001b[0;31m <agent identifier=\"HF\">\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
]
}
],
"source": [
"# %load configs/agents/hf/hf.xml\n",
"<agent identifier=\"HF\">\n",
"<parameter type=\"stock_variables\" name=\"GB\" value=\"40\"></parameter>\n",
"<parameter type=\"stock_variables\" name=\"CB\" value=\"20\"></parameter>\n",
" <parameter type=\"stock_variables\" name=\"Cash\" value=\"10\"></parameter>\n",
" <parameter type=\"stock_variables\" name=\"does_repo\" value=\"yes\"></parameter>\n",
"</agent>\n",
"<!-- <parameter type=\"parameters\" name=\"leverage\" value=\"13.0780116888061\"></parameter> -->\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Those type \" \" names later become dictionaries for the instantiated agent object. So the hedge fund has \n",
"a dictionary (a data structure that saves stuff) with the name stock_variable = {Cash: 20, GB: 40, CB: 20, does_repo = 'yes'} When I write the results to csv, I iterate over those variables.\n",
"You can define additional variables (e.g. leverage) by adding a line. But for now I commented that out. \n",
"Agents' configuration files all look similar to that one. \n",
"The environment config file looks a bit different:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# %load configs/environment/environment_config.xml\n",
"<environment identifier='toy_test'>\n",
"<!-- simulation parameters -->\n",
" <parameter type='static' name='num_sweeps' value='10'></parameter>\n",
" <parameter type='static' name='num_simulations' value='1'></parameter>\n",
" <parameter type='static' name='cbank_directory' value='configs/agents/cbank/'></parameter>\n",
" <parameter type='static' name='dealer_directory' value='configs/agents/dealer/'></parameter>\n",
" <parameter type='static' name='hf_directory' value='configs/agents/hf/'></parameter>\n",
" <parameter type='static' name='pf_directory' value='configs/agents/pf/'></parameter>\n",
" <parameter type='static' name='ic_directory' value='configs/agents/ic/'></parameter>\n",
" <parameter type='static' name='mmf_directory' value='configs/agents/mmf/'></parameter>\n",
" <parameter type='static' name='if_directory' value='configs/agents/if/'></parameter>\n",
" <parameter type='exogenous' name='price_GB' value=\"1.0\"></parameter>\n",
" <parameter type='exogenous' name='price_CB' value=\"1.0\"></parameter>\n",
" <parameter type='exogenous' name='haircut' value=\"0.05\"></parameter>\n",
" <parameter type='exogenous' name='interest_GB' value=\"0.02\"></parameter>\n",
" <parameter type='exogenous' name='interest_CB' value=\"0.04\"></parameter>\n",
" <parameter type='exogenous' name='interest_repo' value=\"0.02\"></parameter>\n",
" <parameter type='exogenous' name='interest_loans' value=\"0.02\"></parameter>\n",
" <parameter type='exogenous' name='interest_deposits' value=\"0.02\"></parameter>\n",
" <parameter type='exogenous' name='GB_shock' value=\"-0.1\"></parameter>\n",
" <parameter type='exogenous' name='CB_shock' value=\"-0.1\"></parameter>\n",
" <parameter type='exogenous' name='Redemption' value=\"-0.1\"></parameter>\n",
"</environment>\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here you can change the initital interest rates and prices for the marketable assets and also the shocks. It's possible to assign them to other variables and change them later in the updater. It's also possible to not read them in at all (just delete the lines) and define those in the updater script, but in the current setup they get read into the dictionary in the environment, environment.exogenous variables = {price_GB : 1.0, ... }. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What's the difference between ```num_simulations``` and ```num_sweeps```? For the time iterations ```current_step``` it's more convenient to use num_sweeps rather than num_simulations for now. ```num_sweeps``` are the time steps for the model algorithm. With num_simulations, one can initiate a different environment with different classes, so for now it's better to stick with num_sweeps to handle the time steps in the model. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Once all the agents' objects and configuration files are instantiated, the code moves on to the actual model algorithm which is stored in the updater class under \\src\\\n",
" ```updater.py```\n",
"\n",
"The updater can be thought as the class that handels the transition. \n",
"\n",
"## Updater.py\n",
"\n",
"Here \n",
"\n",
"- We take over the initial prices and interest rates given by the enviroment config and save them in updater specific dictionaries (updater.prices and updater.rates by using the method ```def add_rates(self, environment):```\n",
"- ```def initialize_prices``` and ```def updade_prices```\n",
"\n",
"- The really important method is the one below: \n",
"\n",
" ```ruby \n",
" def do_update_benchmark(self, environment, current_step, scenario):\n",
" import pandas as pd\n",
"\n",
" if current_step < 1:\n",
" self.add_rates(environment)\n",
" self.initialize_prices(environment, current_step)\n",
"\n",
" print \"***In t=:\", current_step , \" This is the price matrix***\\n\", self.prices, \"\\n\",\n",
"\n",
" self.initialize_assets_all_agents(current_step, environment)\n",
"\n",
" self.profit_all_agents(environment, current_step)\n",
"\n",
" else:\n",
"\n",
" self.update_all_agents_balance_sheets(environment, current_step, scenario)```\n",
" \n",
"- ```def write_to_csv``` puts the output in to a result dataframe self.results_df."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# -*- coding: utf-8 -*-\n",
"\n",
"\n",
"# -------------------------------------------------------------------------\n",
"# class Updater\n",
"# -------------------------------------------------------------------------\n",
"\n",
"import numpy as np\n",
"\n",
"class Updater():\n",
" #\n",
" #\n",
" # METHODS\n",
" #\n",
" def get_identifier(self):\n",
" return self.identifier\n",
"\n",
" # -------------------------------------------------------------------------\n",
" # __init__\n",
" # -------------------------------------------------------------------------\n",
" def __init__(self, environment, runner):\n",
" self.environment = environment\n",
" self.runner = runner\n",
"\n",
" self.results_df = 0\n",
" self.prices = np.array([])\n",
" self.rates={}\n",
"\n",
" self.system_equity = 0\n",
" self.system_assets = 0\n",
"\n",
" self.delta_pGB = 0\n",
" self.delta_pGB = 0\n",
"\n",
" # -------------------------------------------------------------------------\n",
" # -------------------------------------------------------------------------\n",
" # do_update\n",
" # -------------------------------------------------------------------------\n",
" def do_update_benchmark(self, environment, current_step, scenario):\n",
" import pandas as pd\n",
"\n",
" if current_step < 1:\n",
" self.add_rates(environment)\n",
" self.initialize_prices(environment, current_step)\n",
"\n",
" print \"***In t=:\", current_step , \" This is the price matrix***\\n\", self.prices, \"\\n\",\n",
"\n",
" self.initialize_assets_all_agents(current_step, environment)\n",
"\n",
" self.profit_all_agents(environment, current_step)\n",
"\n",
" else:\n",
"\n",
" self.update_all_agents_balance_sheets(environment, current_step, scenario)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Last, but not least, we have the agent classes under /src/class_folder where agents' balance sheets and behavior are set. Profit and balance sheet dynamics are found in the respective agent scripts, i.e. hf.py has the profit functions for the hedge fund, pf.py has the profit function and (potential) constraints for the pension fund, etc. \n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Agent classes "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The functions in the agent scripts are:\n",
"\n",
"```ruby \n",
"def initialize_assets\n",
"def print_balance_shee\n",
"def profit\n",
"def check_consistency\n",
"def update_balance_sheets```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"I hope these instructions are sufficient to get you started. \n",
"\n",
"Please let me know if there is anything else I can do to explain. \n",
"\n",
"Hope you are well. \n",
"\n",
"Tina "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.13"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment