Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix/simplify funding loop #6749

Merged
merged 4 commits into from Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 6 additions & 17 deletions hummingbot/connector/perpetual_derivative_py_base.py
Expand Up @@ -378,13 +378,12 @@ async def _funding_payment_polling_loop(self):
await self._update_all_funding_payments(fire_event_on_new=False) # initialization of the timestamps
while True:
await self._funding_fee_poll_notifier.wait()
success = await self._update_all_funding_payments(fire_event_on_new=True)
if success:
# Only when all tasks are successful would the event notifier be reset
self._funding_fee_poll_notifier = asyncio.Event()
# There is a chance of race condition when the next await allows for a set() to occur before the clear()
# Maybe it is better to use a asyncio.Condition() instead of asyncio.Event()?
self._funding_fee_poll_notifier.clear()
await self._update_all_funding_payments(fire_event_on_new=True)

async def _update_all_funding_payments(self, fire_event_on_new: bool) -> bool:
success = False
async def _update_all_funding_payments(self, fire_event_on_new: bool):
try:
tasks = []
for trading_pair in self.trading_pairs:
Expand All @@ -393,19 +392,9 @@ async def _update_all_funding_payments(self, fire_event_on_new: bool) -> bool:
self._update_funding_payment(trading_pair=trading_pair, fire_event_on_new=fire_event_on_new)
)
)
responses: List[bool] = await safe_gather(*tasks)
success = all(responses)
await safe_gather(*tasks)
except asyncio.CancelledError:
raise
except Exception:
self.logger().network(
"Unexpected error while retrieving funding payments.",
exc_info=True,
app_warning_msg=(
f"Could not fetch funding fee updates for {self.name}. Check API key and network connection."
)
)
return success

async def _update_funding_payment(self, trading_pair: str, fire_event_on_new: bool) -> bool:
fetch_success = True
Expand Down
65 changes: 50 additions & 15 deletions hummingbot/connector/test_support/perpetual_derivative_test.py
Expand Up @@ -706,30 +706,65 @@ def test_listen_for_funding_info_update_updates_funding_info(self, mock_api, moc

self.assertEqual(1, self.exchange._perpetual_trading.funding_info_stream.qsize()) # rest in OB DS tests

# @aioresponses()
# def test_funding_payment_polling_loop_sends_update_event(self, mock_api):
# self._simulate_trading_rules_initialized()
# request_sent_event = asyncio.Event()
# url = self.funding_payment_url
#
# self.async_tasks.append(asyncio.get_event_loop().create_task(self.exchange._funding_payment_polling_loop()))
#
# request_sent_event.clear()
# response = self.funding_payment_mock_response
# mock_api.get(url, body=json.dumps(response), callback=lambda *args, **kwargs: request_sent_event.set())
# self.exchange._funding_fee_poll_notifier.set()
# self.async_run_with_timeout(request_sent_event.wait())
#
# request_sent_event.clear()
# response = self.funding_payment_mock_response
# mock_api.get(url, body=json.dumps(response), callback=lambda *args, **kwargs: request_sent_event.set())
# self.exchange._funding_fee_poll_notifier.set()
# self.async_run_with_timeout(request_sent_event.wait())
#
# self.assertEqual(1, len(self.funding_payment_logger.event_log))
# funding_event: FundingPaymentCompletedEvent = self.funding_payment_logger.event_log[0]
# self.assertEqual(self.target_funding_payment_timestamp, funding_event.timestamp)
# self.assertEqual(self.exchange.name, funding_event.market)
# self.assertEqual(self.trading_pair, funding_event.trading_pair)
# self.assertEqual(self.target_funding_payment_payment_amount, funding_event.amount)
# self.assertEqual(self.target_funding_payment_funding_rate, funding_event.funding_rate)

@aioresponses()
def test_funding_payment_polling_loop_sends_update_event(self, mock_api):
def callback(*args, **kwargs):
request_sent_event.set()

self._simulate_trading_rules_initialized()
request_sent_event = asyncio.Event()
url = self.funding_payment_url

self.async_tasks.append(asyncio.get_event_loop().create_task(self.exchange._funding_payment_polling_loop()))
async def run_test():
response = self.empty_funding_payment_mock_response
mock_api.get(url, body=json.dumps(response), callback=callback)
_ = asyncio.create_task(self.exchange._funding_payment_polling_loop())

response = self.empty_funding_payment_mock_response
mock_api.get(url, body=json.dumps(response), callback=lambda *args, **kwargs: request_sent_event.set())
self.exchange._funding_fee_poll_notifier.set()
self.async_run_with_timeout(request_sent_event.wait())
# Allow task to start - on first pass no event is emitted (initialization)
await asyncio.sleep(0.1)
self.assertEqual(0, len(self.funding_payment_logger.event_log))

request_sent_event.clear()
response = self.funding_payment_mock_response
mock_api.get(url, body=json.dumps(response), callback=lambda *args, **kwargs: request_sent_event.set())
self.exchange._funding_fee_poll_notifier.set()
self.async_run_with_timeout(request_sent_event.wait())
response = self.funding_payment_mock_response
mock_api.get(url, body=json.dumps(response), callback=callback, repeat=True)

request_sent_event.clear()
response = self.funding_payment_mock_response
mock_api.get(url, body=json.dumps(response), callback=lambda *args, **kwargs: request_sent_event.set())
self.exchange._funding_fee_poll_notifier.set()
self.async_run_with_timeout(request_sent_event.wait())
request_sent_event.clear()
self.exchange._funding_fee_poll_notifier.set()
await request_sent_event.wait()
self.assertEqual(1, len(self.funding_payment_logger.event_log))

request_sent_event.clear()
self.exchange._funding_fee_poll_notifier.set()
await request_sent_event.wait()

self.async_run_with_timeout(run_test())

self.assertEqual(1, len(self.funding_payment_logger.event_log))
funding_event: FundingPaymentCompletedEvent = self.funding_payment_logger.event_log[0]
Expand Down