{"action":"created","comment":{"url":"https://api.github.com/repos/quantopian/zipline/pulls/comments/50324200","id":50324200,"diff_hunk":"@@ -11,27 +11,401 @@\n # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n # See the License for the specific language governing permissions and\n # limitations under the License.\n+from textwrap import dedent\n+\n import bcolz\n+from bcolz import ctable\n+import numpy as np\n+from os.path import join\n import json\n import os\n import pandas as pd\n \n MINUTES_PER_DAY = 390\n-\n+DEFAULT_EXPECTEDLEN = 390 * 252 * 15\n+OHLC_RATIO = 1000\n METADATA_FILENAME = 'metadata.json'\n \n \n+class BcolzMinuteOverlappingData(Exception):\n+    pass\n+\n+\n+def _calc_minute_index(market_opens, minutes_per_day):\n+    minutes = np.zeros(len(market_opens) * minutes_per_day,\n+                       dtype='datetime64[ns]')\n+    deltas = np.arange(0, minutes_per_day, dtype='timedelta64[m]')\n+    for i, market_open in enumerate(market_opens):\n+        start = market_open.asm8\n+        minute_values = start + deltas\n+        start_ix = minutes_per_day * i\n+        end_ix = start_ix + minutes_per_day\n+        minutes[start_ix:end_ix] = minute_values\n+    return pd.to_datetime(minutes, utc=True, box=True)\n+\n+\n+def _sid_subdir_path(sid):\n+    \"\"\"\n+    Format subdir path to limit the number directories in any given\n+    subdirectory to 100.\n+\n+    The number in each directory is designed to support at least 100000\n+    equities.\n+\n+    Parameters:\n+    -----------\n+    sid : int\n+        Asset identifier.\n+\n+    Returns:\n+    --------\n+    out : string\n+        A path for the bcolz rootdir, including subdirectory prefixes based on\n+        the padded string representation of the given sid.\n+\n+        e.g. 1 is formatted as 00/00/000001.bcolz\n+    \"\"\"\n+    padded_sid = format(sid, '06')\n+    return os.path.join(\n+        # subdir 1 00/XX\n+        padded_sid[0:2],\n+        # subdir 2 XX/00\n+        padded_sid[2:4],\n+        \"{0}.bcolz\".format(str(padded_sid))\n+    )\n+\n+\n+class BcolzMinuteBarWriter(object):\n+    \"\"\"\n+    Class capable of writing minute OHLCV data to disk into bcolz format.\n+\n+    Writes a bcolz directory for each individual sid, all contained within\n+    a root directory which also contains metadata about the entire dataset.\n+\n+    Each individual asset's data is stored as a bcolz table with a column for\n+    each pricing field: (open, high, low, close, volume)\n+\n+    The open, high, low, and close columns are integers which are 1000 times\n+    the quoted price, so that the data can represented and stored as an\n+    np.uint32, supporting market prices quoted up to the thousands place.\n+\n+    volume is a np.uint32 with no mutation of the tens place.\n+\n+    The 'index' for each individual asset are a repeating period of minutes of\n+    length `minutes_per_day` starting from each market open.\n+    The file format does not account for half-days.\n+    e.g.:\n+    2016-01-19 14:31\n+    2016-01-19 14:32\n+    ...\n+    2016-01-19 20:59\n+    2016-01-19 21:00\n+    2016-01-20 14:31\n+    2016-01-20 14:32\n+    ...\n+    2016-01-20 20:59\n+    2016-01-20 21:00\n+\n+    All assets are written with a common 'index', sharing a common first\n+    trading day. Assets that do not begin trading until after the first trading\n+    day will have zeros for all pricing data up and until data is traded.\n+\n+    'index' is in quotations, because bcolz does not provide an index. The\n+    format allows index-like behavior by writing each minute's data into the\n+    corresponding position of the enumeration of the aforementioned datetime\n+    index.\n+\n+    The datetimes which correspond to each position are written in the metadata\n+    as integer nanoseconds since the epoch into the `minute_index` key.\n+    \"\"\"\n+    def __init__(self,\n+                 first_trading_day,\n+                 rootdir,\n+                 market_opens,\n+                 minutes_per_day=MINUTES_PER_DAY,\n+                 ohlc_ratio=OHLC_RATIO,\n+                 expectedlen=DEFAULT_EXPECTEDLEN):\n+        \"\"\"\n+        Parameters:\n+        -----------\n+\n+        first_trading_day : datetime-like\n+            The first trading day in the data set.\n+        \n+        rootdir : string\n+            Path to the root directory into which to write the metadata and\n+            bcolz subdirectories.\n+\n+        market_opens : pd.Series\n+            The market opens used as a starting point for each periodic span of\n+            minutes in the index.\n+\n+        minutes_per_day : int\n+            The number of minutes per each period. Defaults to 390, the mode\n+            of minutes in NYSE trading days.\n+\n+        ohlc_ratio : int\n+            The ratio by which to multiply the pricing data to convert the floats\n+            from floats to an integer to fit within the np.uint32.\n+\n+            The default is 1000 to support pricing data which comes in to the\n+            thousands place.\n+\n+        expectedlen : int\n+            The expected length of the dataset, used when creating the initial\n+            bcolz ctable.\n+\n+            If the expectedlen is not used, the chunksize and corresponding\n+            compression ratios are not ideal.\n+\n+            Defaults to supporting 15 years of NYSE equity market data.\n+\n+            see: http://bcolz.blosc.org/opt-tips.html#informing-about-the-length-of-your-carrays\n+        \"\"\"\n+        self._rootdir = rootdir\n+        self._first_trading_day = first_trading_day\n+        self._market_opens = market_opens[\n+            market_opens.index.slice_indexer(start=self._first_trading_day)]\n+        self._trading_days = market_opens.index\n+        self._minutes_per_day = minutes_per_day\n+        self._expectedlen = expectedlen\n+        self._ohlc_ratio = ohlc_ratio\n+\n+        self._minute_index = _calc_minute_index(\n+            self._market_opens, self._minutes_per_day)\n+\n+        self._write_metadata()\n+\n+    @property\n+    def first_trading_day(self):\n+        return self._first_trading_day\n+\n+    @property\n+    def metadata_path(self):\n+        return os.path.join(self._rootdir, METADATA_FILENAME)\n+\n+    def _write_metadata(self):\n+        \"\"\"\n+        Write the metadata to a JSON file in the rootdir.\n+\n+        Values contained in the metadata are:\n+        first_trading_day : string\n+            'YYYY-MM-DD' formatted representation of the first trading day\n+             available in the dataset.\n+        minute_index : list of integers\n+             nanosecond integer representation of the minutes, the enumeration of which\n+             corresponds to the values in each bcolz carray.\n+        \"\"\"\n+        metadata = {\n+            'first_trading_day': str(self.first_trading_day.date()),\n+            'minute_index': self._minute_index.asi8.tolist(),\n+            'ohlc_ratio': self._ohlc_ratio,\n+        }\n+        with open(self.metadata_path, 'w+') as fp:\n+            json.dump(metadata, fp)\n+\n+    def sidpath(self, sid):\n+        \"\"\"\n+        Parameters:\n+        -----------\n+        sid : int\n+            Asset identifier.\n+\n+        Returns:\n+        --------\n+        out : string\n+            Full path to the bcolz rootdir for the given sid.\n+        \"\"\"\n+        sid_subdir = _sid_subdir_path(sid)\n+        return join(self._rootdir, sid_subdir)\n+\n+    def last_date_in_output_for_sid(self, sid):\n+        \"\"\"\n+        Parameters:\n+        -----------\n+        sid : int\n+            Asset identifier.\n+\n+        Returns:\n+        --------\n+        out : pd.Timestamp\n+            The midnight of the last date written in to the output for the\n+            given sid.\n+        \"\"\"\n+        try:\n+            sizes_path = \"{0}/close/meta/sizes\".format(self.sidpath(sid))\n+            with open(sizes_path, mode='r') as f:\n+                sizes = f.read()\n+            data = json.loads(sizes)\n+            num_days = data['shape'][0] / self._minutes_per_day\n+            if num_days == 0:\n+                # empty container\n+                return None\n+            return self._trading_days[num_days - 1]\n+        except IOError:","path":"zipline/data/us_equity_minutes.py","position":241,"original_position":242,"commit_id":"edad4eea3fee6644a7618ef8639c1de2c364d3f1","original_commit_id":"a4932dacecc383a65c7a37e882307d3e90405774","user":{"login":"ehebert","id":185744,"avatar_url":"https://avatars.githubusercontent.com/u/185744?v=3","gravatar_id":"","url":"https://api.github.com/users/ehebert","html_url":"https://github.com/ehebert","followers_url":"https://api.github.com/users/ehebert/followers","following_url":"https://api.github.com/users/ehebert/following{/other_user}","gists_url":"https://api.github.com/users/ehebert/gists{/gist_id}","starred_url":"https://api.github.com/users/ehebert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ehebert/subscriptions","organizations_url":"https://api.github.com/users/ehebert/orgs","repos_url":"https://api.github.com/users/ehebert/repos","events_url":"https://api.github.com/users/ehebert/events{/privacy}","received_events_url":"https://api.github.com/users/ehebert/received_events","type":"User","site_admin":false},"body":"This is hit in the case when the ctable has not yet been created.\r\nHowever, before calling this we can just check for ctable existence.","created_at":"2016-01-20T21:44:43Z","updated_at":"2016-01-20T21:44:43Z","html_url":"https://github.com/quantopian/zipline/pull/960#discussion_r50324200","pull_request_url":"https://api.github.com/repos/quantopian/zipline/pulls/960","_links":{"self":{"href":"https://api.github.com/repos/quantopian/zipline/pulls/comments/50324200"},"html":{"href":"https://github.com/quantopian/zipline/pull/960#discussion_r50324200"},"pull_request":{"href":"https://api.github.com/repos/quantopian/zipline/pulls/960"}}},"pull_request":{"url":"https://api.github.com/repos/quantopian/zipline/pulls/960","id":56655206,"html_url":"https://github.com/quantopian/zipline/pull/960","diff_url":"https://github.com/quantopian/zipline/pull/960.diff","patch_url":"https://github.com/quantopian/zipline/pull/960.patch","issue_url":"https://api.github.com/repos/quantopian/zipline/issues/960","number":960,"state":"open","locked":false,"title":"ENH: Add writer for equity minute bcolz format.","user":{"login":"ehebert","id":185744,"avatar_url":"https://avatars.githubusercontent.com/u/185744?v=3","gravatar_id":"","url":"https://api.github.com/users/ehebert","html_url":"https://github.com/ehebert","followers_url":"https://api.github.com/users/ehebert/followers","following_url":"https://api.github.com/users/ehebert/following{/other_user}","gists_url":"https://api.github.com/users/ehebert/gists{/gist_id}","starred_url":"https://api.github.com/users/ehebert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ehebert/subscriptions","organizations_url":"https://api.github.com/users/ehebert/orgs","repos_url":"https://api.github.com/users/ehebert/repos","events_url":"https://api.github.com/users/ehebert/events{/privacy}","received_events_url":"https://api.github.com/users/ehebert/received_events","type":"User","site_admin":false},"body":"Implement a writer for minute data into a format comprised of multiple\r\nctables, one for each individual equity, with a common 'index' shared by\r\nall ctables where a given a dt maps to the same array index for all\r\nequities and fields.\r\n\r\nThis format is pulled from the lazy-mainline/Q2.0 branch, with some\r\nchanges to the interface.\r\n\r\nAdd basic retrieval of values at a given dt to reader. Not yet used by\r\nZipline simulations, but added to support unit tests.\r\n\r\n# Other Notes\r\n\r\nQuestions:\r\n- Currently the main entry point into the writer is `write(sid, days, df)`, where the df is a DataFrame for just the given sid. \r\n-- Providing `days` does feel redundant, when that information could be re-constructed from the `df` and the writer's `self._trading_days`.\r\n-- `sid` could be also be redundant, if the df were formatted with a `MultiIndex` of (sid, dt), then the sids could be iterated over using `get_level_values`.\r\n\r\n@ssanderson I took in a lot of notes from our in person conversation the other day.\r\nIncluding taking in market_opens as a parameter, and then writing out the resulting index to free the writer/reader combo from requiring a `TradingEnvironment` or `tradingcalendar` module.\r\n\r\nWhere I did diverge from our discussion was:\r\n- The writer class no longer requires subclassing to implement different sources, instead the `write` method takes a DataFrame with the OHLCV data. This change resulted from using the writer with our existing and incoming internal dataloader. I found having a writer which was agnostic of its input source more flexible to work with when wiring up different sources, and I believe is a more adoptable public API.\r\n\r\nFor some background on the choice of having the Writer agnostic to the input, I looked to the following:\r\n- https://docs.python.org/2/library/csv.html\r\n- https://golang.org/pkg/bufio/#example_Writer\r\n- http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.to_excel.html\r\n\r\n- The responsibility of the writer is just writing individual sid data, without adding the 'bring data up to date' logic that our internal loader provides. This change allowed dropping the writer into our existing internal loader. If/when we do make that logic a public API, I believe we should make a separate `Loader` (or some other name, `DataSet`/`DataSetManager`, I am not yet sure), which takes the writer as one of its components.\r\n\r\n@jbredeche this implementation differs from our implementation in lazy-mainline in the following ways.\r\n(For reference, https://github.com/quantopian/zipline/blob/lazy-mainline/zipline/data/us_equity_minutes.py)\r\n- The aforementioned change to no longer using subclasses to get the data, instead passing in the DataFrame independent of the data source.\r\n- Making the directory as part of the constructor. This change was 1) based on the above list of other Reader/Writers, 2) was more natural when using the writer with our existing internal loader 3) Allows more flexibility if we ever need to implement another writer that does not write to a directory, e.g. if a Postgres or SQLite writer is implemented then `write(sid, days, df)` would also work with a writer of that type.\r\n\r\n- Allowing multiple passes on writing data, which is a requirement of our internal writers which read the source data in subgroups of days and equities. (Instead of only supporting reading all data for an equity at once.)","created_at":"2016-01-20T19:29:43Z","updated_at":"2016-01-20T21:44:43Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ccde3ad287c21cdf99d47a25321de3d2d7961078","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/quantopian/zipline/pulls/960/commits","review_comments_url":"https://api.github.com/repos/quantopian/zipline/pulls/960/comments","review_comment_url":"https://api.github.com/repos/quantopian/zipline/pulls/comments{/number}","comments_url":"https://api.github.com/repos/quantopian/zipline/issues/960/comments","statuses_url":"https://api.github.com/repos/quantopian/zipline/statuses/edad4eea3fee6644a7618ef8639c1de2c364d3f1","head":{"label":"quantopian:minute-writer-for-one-per-sid","ref":"minute-writer-for-one-per-sid","sha":"edad4eea3fee6644a7618ef8639c1de2c364d3f1","user":{"login":"quantopian","id":1393215,"avatar_url":"https://avatars.githubusercontent.com/u/1393215?v=3","gravatar_id":"","url":"https://api.github.com/users/quantopian","html_url":"https://github.com/quantopian","followers_url":"https://api.github.com/users/quantopian/followers","following_url":"https://api.github.com/users/quantopian/following{/other_user}","gists_url":"https://api.github.com/users/quantopian/gists{/gist_id}","starred_url":"https://api.github.com/users/quantopian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/quantopian/subscriptions","organizations_url":"https://api.github.com/users/quantopian/orgs","repos_url":"https://api.github.com/users/quantopian/repos","events_url":"https://api.github.com/users/quantopian/events{/privacy}","received_events_url":"https://api.github.com/users/quantopian/received_events","type":"Organization","site_admin":false},"repo":{"id":6297520,"name":"zipline","full_name":"quantopian/zipline","owner":{"login":"quantopian","id":1393215,"avatar_url":"https://avatars.githubusercontent.com/u/1393215?v=3","gravatar_id":"","url":"https://api.github.com/users/quantopian","html_url":"https://github.com/quantopian","followers_url":"https://api.github.com/users/quantopian/followers","following_url":"https://api.github.com/users/quantopian/following{/other_user}","gists_url":"https://api.github.com/users/quantopian/gists{/gist_id}","starred_url":"https://api.github.com/users/quantopian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/quantopian/subscriptions","organizations_url":"https://api.github.com/users/quantopian/orgs","repos_url":"https://api.github.com/users/quantopian/repos","events_url":"https://api.github.com/users/quantopian/events{/privacy}","received_events_url":"https://api.github.com/users/quantopian/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/quantopian/zipline","description":"Zipline, a Pythonic Algorithmic Trading Library","fork":false,"url":"https://api.github.com/repos/quantopian/zipline","forks_url":"https://api.github.com/repos/quantopian/zipline/forks","keys_url":"https://api.github.com/repos/quantopian/zipline/keys{/key_id}","collaborators_url":"https://api.github.com/repos/quantopian/zipline/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/quantopian/zipline/teams","hooks_url":"https://api.github.com/repos/quantopian/zipline/hooks","issue_events_url":"https://api.github.com/repos/quantopian/zipline/issues/events{/number}","events_url":"https://api.github.com/repos/quantopian/zipline/events","assignees_url":"https://api.github.com/repos/quantopian/zipline/assignees{/user}","branches_url":"https://api.github.com/repos/quantopian/zipline/branches{/branch}","tags_url":"https://api.github.com/repos/quantopian/zipline/tags","blobs_url":"https://api.github.com/repos/quantopian/zipline/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/quantopian/zipline/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/quantopian/zipline/git/refs{/sha}","trees_url":"https://api.github.com/repos/quantopian/zipline/git/trees{/sha}","statuses_url":"https://api.github.com/repos/quantopian/zipline/statuses/{sha}","languages_url":"https://api.github.com/repos/quantopian/zipline/languages","stargazers_url":"https://api.github.com/repos/quantopian/zipline/stargazers","contributors_url":"https://api.github.com/repos/quantopian/zipline/contributors","subscribers_url":"https://api.github.com/repos/quantopian/zipline/subscribers","subscription_url":"https://api.github.com/repos/quantopian/zipline/subscription","commits_url":"https://api.github.com/repos/quantopian/zipline/commits{/sha}","git_commits_url":"https://api.github.com/repos/quantopian/zipline/git/commits{/sha}","comments_url":"https://api.github.com/repos/quantopian/zipline/comments{/number}","issue_comment_url":"https://api.github.com/repos/quantopian/zipline/issues/comments{/number}","contents_url":"https://api.github.com/repos/quantopian/zipline/contents/{+path}","compare_url":"https://api.github.com/repos/quantopian/zipline/compare/{base}...{head}","merges_url":"https://api.github.com/repos/quantopian/zipline/merges","archive_url":"https://api.github.com/repos/quantopian/zipline/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/quantopian/zipline/downloads","issues_url":"https://api.github.com/repos/quantopian/zipline/issues{/number}","pulls_url":"https://api.github.com/repos/quantopian/zipline/pulls{/number}","milestones_url":"https://api.github.com/repos/quantopian/zipline/milestones{/number}","notifications_url":"https://api.github.com/repos/quantopian/zipline/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/quantopian/zipline/labels{/name}","releases_url":"https://api.github.com/repos/quantopian/zipline/releases{/id}","created_at":"2012-10-19T15:50:29Z","updated_at":"2016-01-20T17:03:33Z","pushed_at":"2016-01-20T21:23:06Z","git_url":"git://github.com/quantopian/zipline.git","ssh_url":"git@github.com:quantopian/zipline.git","clone_url":"https://github.com/quantopian/zipline.git","svn_url":"https://github.com/quantopian/zipline","homepage":"","size":14784,"stargazers_count":2826,"watchers_count":2826,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":818,"mirror_url":null,"open_issues_count":158,"forks":818,"open_issues":158,"watchers":2826,"default_branch":"master"}},"base":{"label":"quantopian:master","ref":"master","sha":"b16e2a7a07aa86df8264595fd3c1b32ff652c412","user":{"login":"quantopian","id":1393215,"avatar_url":"https://avatars.githubusercontent.com/u/1393215?v=3","gravatar_id":"","url":"https://api.github.com/users/quantopian","html_url":"https://github.com/quantopian","followers_url":"https://api.github.com/users/quantopian/followers","following_url":"https://api.github.com/users/quantopian/following{/other_user}","gists_url":"https://api.github.com/users/quantopian/gists{/gist_id}","starred_url":"https://api.github.com/users/quantopian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/quantopian/subscriptions","organizations_url":"https://api.github.com/users/quantopian/orgs","repos_url":"https://api.github.com/users/quantopian/repos","events_url":"https://api.github.com/users/quantopian/events{/privacy}","received_events_url":"https://api.github.com/users/quantopian/received_events","type":"Organization","site_admin":false},"repo":{"id":6297520,"name":"zipline","full_name":"quantopian/zipline","owner":{"login":"quantopian","id":1393215,"avatar_url":"https://avatars.githubusercontent.com/u/1393215?v=3","gravatar_id":"","url":"https://api.github.com/users/quantopian","html_url":"https://github.com/quantopian","followers_url":"https://api.github.com/users/quantopian/followers","following_url":"https://api.github.com/users/quantopian/following{/other_user}","gists_url":"https://api.github.com/users/quantopian/gists{/gist_id}","starred_url":"https://api.github.com/users/quantopian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/quantopian/subscriptions","organizations_url":"https://api.github.com/users/quantopian/orgs","repos_url":"https://api.github.com/users/quantopian/repos","events_url":"https://api.github.com/users/quantopian/events{/privacy}","received_events_url":"https://api.github.com/users/quantopian/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/quantopian/zipline","description":"Zipline, a Pythonic Algorithmic Trading Library","fork":false,"url":"https://api.github.com/repos/quantopian/zipline","forks_url":"https://api.github.com/repos/quantopian/zipline/forks","keys_url":"https://api.github.com/repos/quantopian/zipline/keys{/key_id}","collaborators_url":"https://api.github.com/repos/quantopian/zipline/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/quantopian/zipline/teams","hooks_url":"https://api.github.com/repos/quantopian/zipline/hooks","issue_events_url":"https://api.github.com/repos/quantopian/zipline/issues/events{/number}","events_url":"https://api.github.com/repos/quantopian/zipline/events","assignees_url":"https://api.github.com/repos/quantopian/zipline/assignees{/user}","branches_url":"https://api.github.com/repos/quantopian/zipline/branches{/branch}","tags_url":"https://api.github.com/repos/quantopian/zipline/tags","blobs_url":"https://api.github.com/repos/quantopian/zipline/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/quantopian/zipline/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/quantopian/zipline/git/refs{/sha}","trees_url":"https://api.github.com/repos/quantopian/zipline/git/trees{/sha}","statuses_url":"https://api.github.com/repos/quantopian/zipline/statuses/{sha}","languages_url":"https://api.github.com/repos/quantopian/zipline/languages","stargazers_url":"https://api.github.com/repos/quantopian/zipline/stargazers","contributors_url":"https://api.github.com/repos/quantopian/zipline/contributors","subscribers_url":"https://api.github.com/repos/quantopian/zipline/subscribers","subscription_url":"https://api.github.com/repos/quantopian/zipline/subscription","commits_url":"https://api.github.com/repos/quantopian/zipline/commits{/sha}","git_commits_url":"https://api.github.com/repos/quantopian/zipline/git/commits{/sha}","comments_url":"https://api.github.com/repos/quantopian/zipline/comments{/number}","issue_comment_url":"https://api.github.com/repos/quantopian/zipline/issues/comments{/number}","contents_url":"https://api.github.com/repos/quantopian/zipline/contents/{+path}","compare_url":"https://api.github.com/repos/quantopian/zipline/compare/{base}...{head}","merges_url":"https://api.github.com/repos/quantopian/zipline/merges","archive_url":"https://api.github.com/repos/quantopian/zipline/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/quantopian/zipline/downloads","issues_url":"https://api.github.com/repos/quantopian/zipline/issues{/number}","pulls_url":"https://api.github.com/repos/quantopian/zipline/pulls{/number}","milestones_url":"https://api.github.com/repos/quantopian/zipline/milestones{/number}","notifications_url":"https://api.github.com/repos/quantopian/zipline/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/quantopian/zipline/labels{/name}","releases_url":"https://api.github.com/repos/quantopian/zipline/releases{/id}","created_at":"2012-10-19T15:50:29Z","updated_at":"2016-01-20T17:03:33Z","pushed_at":"2016-01-20T21:23:06Z","git_url":"git://github.com/quantopian/zipline.git","ssh_url":"git@github.com:quantopian/zipline.git","clone_url":"https://github.com/quantopian/zipline.git","svn_url":"https://github.com/quantopian/zipline","homepage":"","size":14784,"stargazers_count":2826,"watchers_count":2826,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":818,"mirror_url":null,"open_issues_count":158,"forks":818,"open_issues":158,"watchers":2826,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/quantopian/zipline/pulls/960"},"html":{"href":"https://github.com/quantopian/zipline/pull/960"},"issue":{"href":"https://api.github.com/repos/quantopian/zipline/issues/960"},"comments":{"href":"https://api.github.com/repos/quantopian/zipline/issues/960/comments"},"review_comments":{"href":"https://api.github.com/repos/quantopian/zipline/pulls/960/comments"},"review_comment":{"href":"https://api.github.com/repos/quantopian/zipline/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/quantopian/zipline/pulls/960/commits"},"statuses":{"href":"https://api.github.com/repos/quantopian/zipline/statuses/edad4eea3fee6644a7618ef8639c1de2c364d3f1"}}}}