Python 3.9 - Scheduling periodic calls of async function with different parameters

Viewed 3076

How to in python 3.9 implement the functionality of calling the async functions with different parameters, by scheduled periods? The functionality should be working on any OS (Linux, Windows, Mac)

I have a function fetchOHLCV which downloads market data from exchanges. The function has two input parameters - pair, timeframe. Depending on the pair and timeframe values the function download data from exchanges and stores them in DB.

The goal - call this function with different periods with different parameters.

1) fetchOHLCV(pair ='EUR/USD', timeframe="1m") - each minute
2) fetchOHLCV(pair ='EUR/USD', timeframe="1h") - each new hour.
3) fetchOHLCV(pair ='EUR/USD', timeframe="1d") - each new day 
4) fetchOHLCV(pair ='EUR/USD', timeframe="1w") - each new week

At this moment I don't have experience working with scheduling in python and I don't know which libraries will optimal for my task and I'm interested in the best practices of implementing similar tasks.

2 Answers

Here you use apschedulersAsyncIOScheduler which works naturally with async functions

scheduler = AsyncIOScheduler()
scheduler.add_job(fetchOHLCV, trigger=tr)
scheduler.start()

tr is trigger object. You can use either IntervalTrigger or a CronTriggerto schedule it. Its recommended to do a shutdown() on the scheduler object after the end of program

OR alternatively

You can use run_coroutine_threadsafeto schedule a coroutine to the event loop

asyncio.run_coroutine_threadsafe(async_function(), bot.loop)

Working example of asyncio on Python3.9

import asyncio

async def periodic():
    while True:
        print('periodic')
        await asyncio.sleep(1) #you can put 900 seconds = 15mins

def stop():
    task.cancel()

loop = asyncio.get_event_loop()
loop.call_later(5, stop) #increase end time as per your requirement
task = loop.create_task(periodic())

try:
    loop.run_until_complete(task)
except asyncio.CancelledError:
    pass

implementation

So as you can see async function was called with the scheduling of 1second and stop function was called at 5th second. Try implementing this and could possibly solve your problem

As a ready-to-use solution, you could use aiocron library. If you are not familiar with cron expression syntax, you can use this online editor to check.

Example (this will work on any OS):

import asyncio
from datetime import datetime
import aiocron


async def foo(param):
    print(datetime.now().time(), param)


async def main():
    cron_min = aiocron.crontab('*/1 * * * *', func=foo, args=("At every minute",), start=True)
    cron_hour = aiocron.crontab('0 */1 * * *', func=foo, args=("At minute 0 past every hour.",), start=True)
    cron_day = aiocron.crontab('0 9 */1 * *', func=foo, args=("At 09:00 on every day-of-month",), start=True)
    cron_week = aiocron.crontab('0 9 * * Mon', func=foo, args=("At 09:00 on every Monday",), start=True)

    while True:
        await asyncio.sleep(1)

asyncio.run(main())

Output:

15:26:00.003226 At every minute
15:27:00.002642 At every minute
...
Related