-
Notifications
You must be signed in to change notification settings - Fork 0
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 #12 from bsa7/SMLP-011-implement-data-fetcher
SMLP-011 Implement data fetcher class
- Loading branch information
Showing
10 changed files
with
157 additions
and
34 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
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,44 @@ | ||
''' This file contains a DataFetcher class - this class working with data: load data, store data ''' | ||
from datetime import datetime | ||
# from app.lib.env import Env | ||
|
||
class DataFetcher(): | ||
''' This class fetches new portion of data from desired source. ''' | ||
DEFAULT_FETCH_INTERVAL = 1 * 60000 # 1.minute | ||
|
||
def __init__(self, | ||
api_client, | ||
from_timestamp = None, | ||
to_timestamp = None, | ||
fetch_interval_size = DEFAULT_FETCH_INTERVAL): | ||
self.__from_timestamp = from_timestamp | ||
self.__to_timestamp = to_timestamp | ||
self.__api_client = api_client | ||
self.__fetch_interval_size = fetch_interval_size | ||
|
||
def update(self, symbol: str): | ||
''' This method look over previous stored data and fetch new data ''' | ||
start_timestamp = self.__start_timestamp(symbol) | ||
return self.__api_client.fetch_data_in_batches(symbol = symbol, | ||
from_timestamp = start_timestamp, | ||
to_timestamp = self.__finish_timestamp, | ||
batch_size_in_milliseconds = self.__fetch_interval_size) | ||
|
||
def __start_timestamp(self, symbol: str) -> int: | ||
''' This method determines the last point in time beyond which the required | ||
data is stored in the system. In fact, this moment plus one millisecond | ||
is the start for the time interval for which the data will be received. ''' | ||
# In this point we would to find last data of time series in our db | ||
print(f'{symbol=}') | ||
if self.__from_timestamp is not None: | ||
return self.__from_timestamp | ||
|
||
return self.__finish_timestamp - self.__fetch_interval_size | ||
|
||
@property | ||
def __finish_timestamp(self) -> int: | ||
''' This method always returns current timestamp ''' | ||
if self.__to_timestamp is not None: | ||
return self.__to_timestamp | ||
|
||
return int(datetime.now().timestamp()) |
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,19 @@ | ||
''' This file contains client for time series database ''' | ||
from datetime import datetime | ||
from app.lib.singleton import Singleton | ||
|
||
class DbClient(Singleton): | ||
''' This class contains client for database ''' | ||
def __init__(self): | ||
''' Initialize connection ''' | ||
self.connection = None | ||
|
||
def find_latest_timestamp_for_symbol(self, symbol: str) -> dict: | ||
''' This method finds the most recently stored value for a given pair and | ||
returns a timestamp of that value. ''' | ||
result = { | ||
'symbol': symbol, | ||
'timestamp': datetime.now().timestamp() - 2 * 60000 # 2 minutes from now | ||
} | ||
|
||
return result |
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 |
---|---|---|
@@ -1,9 +1,8 @@ | ||
''' This file run methods for data creation ''' | ||
from app.lib.api_exmo_client import ApiExmoClient | ||
# from app.lib.utils import timestamp_to_formatteddatetime | ||
from app.lib.data_fetcher import DataFetcher | ||
|
||
# print(timestamp_to_formatteddatetime(1585557000000)) | ||
|
||
result = ApiExmoClient().candles_history('BTC_USDT', 1585551900, 1585552000) | ||
data_fetcher = DataFetcher(api_client = ApiExmoClient(), fetch_interval_size = 60 * 1000) | ||
result = data_fetcher.update('BTC_USDT') | ||
|
||
print(f'{result=}') |
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 |
---|---|---|
@@ -1,3 +1,3 @@ | ||
#!/usr/bin/env bash | ||
|
||
python -m pytest test | ||
python -m pytest test --capture=sys |
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,27 @@ | ||
''' This file contains unit tests for app/lib/data_fetcher.py ''' | ||
import unittest | ||
import responses | ||
from app.lib.data_fetcher import DataFetcher | ||
from app.lib.api_exmo_client import ApiExmoClient | ||
from app.types.api_exmo_responses import CandlesHistory | ||
from test.support.mock_helper import stub_get_request | ||
|
||
class TestDataFetcher(unittest.TestCase): | ||
''' This class contains tests for DataFetcher class ''' | ||
def test_update(self): | ||
''' This case runs the Update method to ensure that the third party API | ||
call is being made and that the data received from both requests is | ||
being accumulated. ''' | ||
uri1 = 'https://api.exmo.com/v1.1/candles_history?from=1585551901&resolution=1&symbol=BTC_USDT&to=1585551910' | ||
uri2 = 'https://api.exmo.com/v1.1/candles_history?from=1585551911&resolution=1&symbol=BTC_USDT&to=1585551920' | ||
expected_response1: CandlesHistory = { 'candles': [{ 't': 1 }] } | ||
expected_response2: CandlesHistory = { 'candles': [{ 't': 2 }] } | ||
data_fetcher = DataFetcher(api_client = ApiExmoClient(), | ||
from_timestamp = 1585551900, | ||
to_timestamp = 1585551920, | ||
fetch_interval_size = 10) | ||
with responses.RequestsMock() as rsps: | ||
stub_get_request(rsps, uri1, expected_response1) | ||
stub_get_request(rsps, uri2, expected_response2) | ||
result = data_fetcher.update(symbol = 'BTC_USDT') | ||
self.assertEqual(result, expected_response1['candles'] + expected_response2['candles']) |
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,6 @@ | ||
''' This file contain helpers for mock external service responses ''' | ||
|
||
def stub_get_request(rsps, api_uri: str, response: dict): | ||
''' This method creates a stub for a specific api endpoint and emulates a | ||
successful data fetch ''' | ||
rsps.get(api_uri, json = response, status = 200) |