-
Notifications
You must be signed in to change notification settings - Fork 851
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #153 from mhallsmoore/iqfeed_price_handler
Added a DTN IQFeed Price Handler. Also modified drawdown and drawdown…
- Loading branch information
Showing
8 changed files
with
182 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import os | ||
|
||
import pandas as pd | ||
|
||
from ..price_parser import PriceParser | ||
from .base import AbstractBarPriceHandler | ||
from ..event import BarEvent | ||
|
||
|
||
class IQFeedIntradayCsvBarPriceHandler(AbstractBarPriceHandler): | ||
""" | ||
IQFeedIntradayCsvBarPriceHandler is designed to read | ||
intraday bar CSV files downloaded from DTN IQFeed, consisting | ||
of Open-Low-High-Close-Volume-OpenInterest (OHLCVI) data | ||
for each requested financial instrument and stream those to | ||
the provided events queue as BarEvents. | ||
""" | ||
def __init__( | ||
self, csv_dir, events_queue, | ||
init_tickers=None, | ||
start_date=None, end_date=None | ||
): | ||
""" | ||
Takes the CSV directory, the events queue and a possible | ||
list of initial ticker symbols then creates an (optional) | ||
list of ticker subscriptions and associated prices. | ||
""" | ||
self.csv_dir = csv_dir | ||
self.events_queue = events_queue | ||
self.continue_backtest = True | ||
self.tickers = {} | ||
self.tickers_data = {} | ||
if init_tickers is not None: | ||
for ticker in init_tickers: | ||
self.subscribe_ticker(ticker) | ||
self.start_date = start_date | ||
self.end_date = end_date | ||
self.bar_stream = self._merge_sort_ticker_data() | ||
|
||
def _open_ticker_price_csv(self, ticker): | ||
""" | ||
Opens the CSV files containing the equities ticks from | ||
the specified CSV data directory, converting them into | ||
them into a pandas DataFrame, stored in a dictionary. | ||
""" | ||
ticker_path = os.path.join(self.csv_dir, "%s.csv" % ticker) | ||
|
||
self.tickers_data[ticker] = pd.read_csv( | ||
ticker_path, | ||
names=[ | ||
"Date", "Open", "Low", "High", | ||
"Close", "Volume", "OpenInterest" | ||
], | ||
index_col="Date", parse_dates=True | ||
) | ||
self.tickers_data[ticker]["Ticker"] = ticker | ||
|
||
def _merge_sort_ticker_data(self): | ||
""" | ||
Concatenates all of the separate equities DataFrames | ||
into a single DataFrame that is time ordered, allowing tick | ||
data events to be added to the queue in a chronological fashion. | ||
Note that this is an idealised situation, utilised solely for | ||
backtesting. In live trading ticks may arrive "out of order". | ||
""" | ||
df = pd.concat(self.tickers_data.values()).sort_index() | ||
start = None | ||
end = None | ||
if self.start_date is not None: | ||
start = df.index.searchsorted(self.start_date) | ||
if self.end_date is not None: | ||
end = df.index.searchsorted(self.end_date) | ||
# Determine how to slice | ||
if start is None and end is None: | ||
return df.iterrows() | ||
elif start is not None and end is None: | ||
return df.ix[start:].iterrows() | ||
elif start is None and end is not None: | ||
return df.ix[:end].iterrows() | ||
else: | ||
return df.ix[start:end].iterrows() | ||
|
||
def subscribe_ticker(self, ticker): | ||
""" | ||
Subscribes the price handler to a new ticker symbol. | ||
""" | ||
if ticker not in self.tickers: | ||
try: | ||
self._open_ticker_price_csv(ticker) | ||
dft = self.tickers_data[ticker] | ||
row0 = dft.iloc[0] | ||
|
||
close = PriceParser.parse(row0["Close"]) | ||
|
||
ticker_prices = { | ||
"close": close, | ||
"adj_close": close, | ||
"timestamp": dft.index[0] | ||
} | ||
self.tickers[ticker] = ticker_prices | ||
except OSError: | ||
print( | ||
"Could not subscribe ticker %s " | ||
"as no data CSV found for pricing." % ticker | ||
) | ||
else: | ||
print( | ||
"Could not subscribe ticker %s " | ||
"as is already subscribed." % ticker | ||
) | ||
|
||
def _create_event(self, index, period, ticker, row): | ||
""" | ||
Obtain all elements of the bar from a row of dataframe | ||
and return a BarEvent | ||
""" | ||
open_price = PriceParser.parse(row["Open"]) | ||
low_price = PriceParser.parse(row["Low"]) | ||
high_price = PriceParser.parse(row["High"]) | ||
close_price = PriceParser.parse(row["Close"]) | ||
adj_close_price = PriceParser.parse(row["Close"]) | ||
volume = int(row["Volume"]) | ||
bev = BarEvent( | ||
ticker, index, period, open_price, | ||
high_price, low_price, close_price, | ||
volume, adj_close_price | ||
) | ||
return bev | ||
|
||
def stream_next(self): | ||
""" | ||
Place the next BarEvent onto the event queue. | ||
""" | ||
try: | ||
index, row = next(self.bar_stream) | ||
except StopIteration: | ||
self.continue_backtest = False | ||
return | ||
# Obtain all elements of the bar from the dataframe | ||
ticker = row["Ticker"] | ||
period = 60 # Seconds in a minute | ||
# Create the tick event for the queue | ||
bev = self._create_event(index, period, ticker, row) | ||
# Store event | ||
self._store_event(bev) | ||
# Send event to queue | ||
self.events_queue.put(bev) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters