I would use my objectScript()
expression function’s state
dictionary to hold the last few samples of each tag in memory (with timestamps) and calculate from those. Best if delegated to a function in the global scripting project. If you are particular about accuracy at startup, you can populate empty state from the historian, then track tag change from there.
You’ll need this free module: