PageRenderTime 24ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/zipline/assets/synthetic.py

https://gitlab.com/lbennett/zipline
Python | 257 lines | 216 code | 6 blank | 35 comment | 1 complexity | 65abeb63f60b151c16b95174fe60dce6 MD5 | raw file
  1. from itertools import product
  2. from string import ascii_uppercase
  3. import pandas as pd
  4. from pandas.tseries.offsets import MonthBegin
  5. from six import iteritems
  6. from .futures import CME_CODE_TO_MONTH
  7. def make_rotating_equity_info(num_assets,
  8. first_start,
  9. frequency,
  10. periods_between_starts,
  11. asset_lifetime):
  12. """
  13. Create a DataFrame representing lifetimes of assets that are constantly
  14. rotating in and out of existence.
  15. Parameters
  16. ----------
  17. num_assets : int
  18. How many assets to create.
  19. first_start : pd.Timestamp
  20. The start date for the first asset.
  21. frequency : str or pd.tseries.offsets.Offset (e.g. trading_day)
  22. Frequency used to interpret next two arguments.
  23. periods_between_starts : int
  24. Create a new asset every `frequency` * `periods_between_new`
  25. asset_lifetime : int
  26. Each asset exists for `frequency` * `asset_lifetime` days.
  27. Returns
  28. -------
  29. info : pd.DataFrame
  30. DataFrame representing newly-created assets.
  31. """
  32. return pd.DataFrame(
  33. {
  34. 'symbol': [chr(ord('A') + i) for i in range(num_assets)],
  35. # Start a new asset every `periods_between_starts` days.
  36. 'start_date': pd.date_range(
  37. first_start,
  38. freq=(periods_between_starts * frequency),
  39. periods=num_assets,
  40. ),
  41. # Each asset lasts for `asset_lifetime` days.
  42. 'end_date': pd.date_range(
  43. first_start + (asset_lifetime * frequency),
  44. freq=(periods_between_starts * frequency),
  45. periods=num_assets,
  46. ),
  47. 'exchange': 'TEST',
  48. },
  49. index=range(num_assets),
  50. )
  51. def make_simple_equity_info(sids,
  52. start_date,
  53. end_date,
  54. symbols=None):
  55. """
  56. Create a DataFrame representing assets that exist for the full duration
  57. between `start_date` and `end_date`.
  58. Parameters
  59. ----------
  60. sids : array-like of int
  61. start_date : pd.Timestamp, optional
  62. end_date : pd.Timestamp, optional
  63. symbols : list, optional
  64. Symbols to use for the assets.
  65. If not provided, symbols are generated from the sequence 'A', 'B', ...
  66. Returns
  67. -------
  68. info : pd.DataFrame
  69. DataFrame representing newly-created assets.
  70. """
  71. num_assets = len(sids)
  72. if symbols is None:
  73. symbols = list(ascii_uppercase[:num_assets])
  74. return pd.DataFrame(
  75. {
  76. 'symbol': list(symbols),
  77. 'start_date': pd.to_datetime([start_date] * num_assets),
  78. 'end_date': pd.to_datetime([end_date] * num_assets),
  79. 'exchange': 'TEST',
  80. },
  81. index=sids,
  82. columns=(
  83. 'start_date',
  84. 'end_date',
  85. 'symbol',
  86. 'exchange',
  87. ),
  88. )
  89. def make_jagged_equity_info(num_assets,
  90. start_date,
  91. first_end,
  92. frequency,
  93. periods_between_ends,
  94. auto_close_delta):
  95. """
  96. Create a DataFrame representing assets that all begin at the same start
  97. date, but have cascading end dates.
  98. Parameters
  99. ----------
  100. num_assets : int
  101. How many assets to create.
  102. start_date : pd.Timestamp
  103. The start date for all the assets.
  104. first_end : pd.Timestamp
  105. The date at which the first equity will end.
  106. frequency : str or pd.tseries.offsets.Offset (e.g. trading_day)
  107. Frequency used to interpret the next argument.
  108. periods_between_ends : int
  109. Starting after the first end date, end each asset every
  110. `frequency` * `periods_between_ends`.
  111. Returns
  112. -------
  113. info : pd.DataFrame
  114. DataFrame representing newly-created assets.
  115. """
  116. frame = pd.DataFrame(
  117. {
  118. 'symbol': [chr(ord('A') + i) for i in range(num_assets)],
  119. 'start_date': start_date,
  120. 'end_date': pd.date_range(
  121. first_end,
  122. freq=(periods_between_ends * frequency),
  123. periods=num_assets,
  124. ),
  125. 'exchange': 'TEST',
  126. },
  127. index=range(num_assets),
  128. )
  129. # Explicitly pass None to disable setting the auto_close_date column.
  130. if auto_close_delta is not None:
  131. frame['auto_close_date'] = frame['end_date'] + auto_close_delta
  132. return frame
  133. def make_future_info(first_sid,
  134. root_symbols,
  135. years,
  136. notice_date_func,
  137. expiration_date_func,
  138. start_date_func,
  139. month_codes=None):
  140. """
  141. Create a DataFrame representing futures for `root_symbols` during `year`.
  142. Generates a contract per triple of (symbol, year, month) supplied to
  143. `root_symbols`, `years`, and `month_codes`.
  144. Parameters
  145. ----------
  146. first_sid : int
  147. The first sid to use for assigning sids to the created contracts.
  148. root_symbols : list[str]
  149. A list of root symbols for which to create futures.
  150. years : list[int or str]
  151. Years (e.g. 2014), for which to produce individual contracts.
  152. notice_date_func : (Timestamp) -> Timestamp
  153. Function to generate notice dates from first of the month associated
  154. with asset month code. Return NaT to simulate futures with no notice
  155. date.
  156. expiration_date_func : (Timestamp) -> Timestamp
  157. Function to generate expiration dates from first of the month
  158. associated with asset month code.
  159. start_date_func : (Timestamp) -> Timestamp, optional
  160. Function to generate start dates from first of the month associated
  161. with each asset month code. Defaults to a start_date one year prior
  162. to the month_code date.
  163. month_codes : dict[str -> [1..12]], optional
  164. Dictionary of month codes for which to create contracts. Entries
  165. should be strings mapped to values from 1 (January) to 12 (December).
  166. Default is zipline.futures.CME_CODE_TO_MONTH
  167. Returns
  168. -------
  169. futures_info : pd.DataFrame
  170. DataFrame of futures data suitable for passing to an AssetDBWriter.
  171. """
  172. if month_codes is None:
  173. month_codes = CME_CODE_TO_MONTH
  174. year_strs = list(map(str, years))
  175. years = [pd.Timestamp(s, tz='UTC') for s in year_strs]
  176. # Pairs of string/date like ('K06', 2006-05-01)
  177. contract_suffix_to_beginning_of_month = tuple(
  178. (month_code + year_str[-2:], year + MonthBegin(month_num))
  179. for ((year, year_str), (month_code, month_num))
  180. in product(
  181. zip(years, year_strs),
  182. iteritems(month_codes),
  183. )
  184. )
  185. contracts = []
  186. parts = product(root_symbols, contract_suffix_to_beginning_of_month)
  187. for sid, (root_sym, (suffix, month_begin)) in enumerate(parts, first_sid):
  188. contracts.append({
  189. 'sid': sid,
  190. 'root_symbol': root_sym,
  191. 'symbol': root_sym + suffix,
  192. 'start_date': start_date_func(month_begin),
  193. 'notice_date': notice_date_func(month_begin),
  194. 'expiration_date': notice_date_func(month_begin),
  195. 'multiplier': 500,
  196. })
  197. return pd.DataFrame.from_records(contracts, index='sid').convert_objects()
  198. def make_commodity_future_info(first_sid,
  199. root_symbols,
  200. years,
  201. month_codes=None):
  202. """
  203. Make futures testing data that simulates the notice/expiration date
  204. behavior of physical commodities like oil.
  205. Parameters
  206. ----------
  207. first_sid : int
  208. root_symbols : list[str]
  209. years : list[int]
  210. month_codes : dict[str -> int]
  211. Expiration dates are on the 20th of the month prior to the month code.
  212. Notice dates are are on the 20th two months prior to the month code.
  213. Start dates are one year before the contract month.
  214. See Also
  215. --------
  216. make_future_info
  217. """
  218. nineteen_days = pd.Timedelta(days=19)
  219. one_year = pd.Timedelta(days=365)
  220. return make_future_info(
  221. first_sid=first_sid,
  222. root_symbols=root_symbols,
  223. years=years,
  224. notice_date_func=lambda dt: dt - MonthBegin(2) + nineteen_days,
  225. expiration_date_func=lambda dt: dt - MonthBegin(1) + nineteen_days,
  226. start_date_func=lambda dt: dt - one_year,
  227. month_codes=month_codes,
  228. )