In [1]:
%load_ext autoreload
In [2]:
autoreload 2
In [3]:
%matplotlib inline
In [22]:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import statsmodels.api as sm
import plotly
import cufflinks as cf
from plotly import graph_objs as go
import vizualizations
plotly.offline.init_notebook_mode()
cf.set_config_file(offline=True, theme='white')
In [5]:
!sbt "run-main ZeroIntelligenceApp"
In [6]:
# this is a bit of a hack as current log files are not valid JSON!
with open('./data/fills.log') as data_file:
zi_data = pd.read_json('[%s]' % ','.join(data_file.read().splitlines()))
zi_data.set_index('timestamp', inplace=True)
In [7]:
zi_data.describe()
Out[7]:
In [8]:
zi_data['spread'] = zi_data.bidPrice - zi_data.askPrice
In [9]:
zi_data.spread.describe()
Out[9]:
Note that raw returns are bounded below! Bounds on price (at least in these simulations!) are $1 \le p_t \le \overline{p}$. Therefore lower bound on raw returns is...
$$ \underline{r} = \frac{1 - \overline{p}}{\overline{p}} \approx -1. $$Similarly, then upper bound on raw returns is...
$$ \underline{r} = \frac{\overline{p} - 1}{1} \approx \overline{p}. $$
In [10]:
zi_data['raw_returns'] = zi_data.price.pct_change(periods=1)
In [11]:
zi_data.raw_returns.describe()
Out[11]:
In [12]:
zi_data.raw_returns.iplot(xTitle='Time', yTitle='Return', title='Raw returns with unconstrained ZIA',
dimensions=(800, 500))
Starting from raw returns, $r_{t+k}$ we see that...
$$ 1 + r_{t+k} = 1 + \frac{p_{t+k} - p_t}{p_t} = \frac{p_{t+k}}{p_t} $$...taking logs yields...
$$ \ln \big(1 + r_{t+k}\big) = \ln p_{t+k} - \ln p_t = \Delta \ln p_{t+k} $$...since $\ln \big(1 + r_{t+k}\big) \approx r_{t+k}$ for $r << 1$ we should expect that raw and logarithmic return formulas should yields similar results for "small" returns.
In [13]:
zi_data['log_returns'] = np.log(1 + zi_data.raw_returns)
In [14]:
zi_data['mid_price'] = 0.5 * (zi_data.askPrice + zi_data.bidPrice)
How to best measure effective size? Particularly of ask orders!
In [15]:
zi_data['effective_size'] = zi_data.quantity
incoming_ask_orders = zi_data.bidPrice == zi_data.price
zi_data.loc[incoming_ask_orders, 'effective_size'] *= -zi_data.loc[incoming_ask_orders, 'askPrice']
incoming_bid_orders = zi_data.askPrice == zi_data.price
zi_data.loc[incoming_bid_orders, 'effective_size'] *= zi_data.loc[incoming_bid_orders, 'bidPrice']
Compute the measure of price impact: $\Delta \ln$ mid_price...
In [16]:
zi_data['price_impact'] = np.log(zi_data.mid_price).diff()
In [17]:
zi_data[incoming_ask_orders].head()
Out[17]:
In [20]:
zi_data.iplot(kind='scatter', x='effective_size', y='price_impact', mode='markers', size=3,
xTitle='Effective Size', yTitle='Price Impact', title='Price impact with unconstrained ZIA',
dimensions=(800, 500))
In [19]:
grouped_data = zi_data.groupby("effective_size")
grouped_data.price_impact.mean().iplot(kind='line', xTitle='Effective Size', yTitle='Price Impact',
title='Price impact with unconstrained ZIA', dimensions=(800, 500))
In [23]:
# incoming bid orders
fig, ax = plt.subplots(1, 1, figsize=(10, 8))
grouped_data = zi_data.groupby("effective_size")
grouped_data.price_impact.mean().plot(color='r', alpha=0.75, ax=ax)
ax.scatter(zi_data.effective_size, zi_data.price_impact, edgecolor='b', s=1, alpha=0.05)
ax.set_ylabel("price_impact")
plt.show()
In [25]:
fig = vizualizations.ecdf_plot(zi_data.log_returns.abs(), upper=True, figure_title="Zero Intelligence Agents",
xaxis_type='log', xaxis_title='Absolute Logarithmic Returns', yaxis_type='log')
plotly.offline.iplot(fig)
In [26]:
fig = vizualizations.ecdf_plot(zi_data.raw_returns.abs(), upper=True, figure_title="Zero Intelligence Agents",
xaxis_type='log', xaxis_title='Absolute Raw Returns', yaxis_type='log')
plotly.offline.iplot(fig)
Endow traders with exogenous valuations and impose the requirement that traders never offer to buy (sell) a tradable at a price that is higher (lower) than their respective valuations of the tradable. Traders still choose their limit prices randomly, so in this sense traders still have "zero intelligence," its just that the support of the distribution from which these random limit prices are drawn is truncated to reflect their valuations.
In [27]:
!sbt "run-main ZeroIntelligenceConstrainedApp"
In [28]:
# this is a bit of a hack as current log files are not valid JSON!
with open('./data/fills.log') as data_file:
zic_data = pd.read_json('[%s]' % ','.join(data_file.read().splitlines()))
zic_data.set_index('timestamp', inplace=True)
In [29]:
zic_data.describe()
Out[29]:
In [30]:
zic_data['spread'] = zic_data.bidPrice - zic_data.askPrice
zic_data['raw_returns'] = zic_data.price.pct_change(periods=1)
zic_data['log_returns'] = np.log(1 + zic_data.raw_returns)
In [31]:
zic_data.price.iplot(xTitle='Time', yrange=[0, 200], yTitle='Asset Price',
title='Asset prices with constrained ZIA')
In [32]:
zic_data.spread.iplot(xTitle='Time', yrange=[0, 200], yTitle='Bid-Ask Spread',
title='Spread with constrained ZIA')
In [33]:
zic_data.log_returns.iplot(xTitle='Time', yTitle='Return', title='Logarithmic returns with unconstrained ZIA')
In [34]:
zi_data.spread.describe()
Out[34]:
In [35]:
zic_data.spread.describe()
Out[35]:
In [ ]:
# render the plot locally in the notebook
fig = vizualizations.kde_plot([zi_data.spread, zic_data.spread], figure_title="Zero Intelligence Agents",
xaxis_title='Bid-Ask Spread', xaxis_range=[1, 200])
plotly.offline.iplot(fig)
In [43]:
zi_data.log_returns.describe()
Out[43]:
In [44]:
zic_data.log_returns.describe()
Out[44]:
In [307]:
# render the plot locally in the notebook
fig = kde_plot([zi_data.log_returns, zic_data.log_returns], figure_title="Zero Intelligence Agents",
xaxis_title='Logarithmic Returns')
plotly.offline.iplot(fig)
In [ ]: