/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace QuantConnect.Util.RateLimit
{
///
/// Provides a refill strategy that has a constant, quantized refill rate.
/// For example, after 1 minute passes add 5 units. If 59 seconds has passed, it will add zero unit,
/// but if 2 minutes have passed, then 10 units would be added.
///
public class FixedIntervalRefillStrategy : IRefillStrategy
{
private readonly object _sync = new object();
private long _nextRefillTimeTicks;
private readonly long _refillAmount;
private readonly long _refillIntervalTicks;
private readonly ITimeProvider _timeProvider;
///
/// Initializes a new instance of the class.
///
/// Provides the current time used for determining how much time has elapsed
/// between invocations of the refill method
/// Defines the constant number of tokens to be made available for consumption
/// each time the provided has passed
/// The amount of time that must pass before adding the specified
/// back to the bucket
public FixedIntervalRefillStrategy(ITimeProvider timeProvider, long refillAmount, TimeSpan refillInterval)
{
_timeProvider = timeProvider;
_refillAmount = refillAmount;
_refillIntervalTicks = refillInterval.Ticks;
_nextRefillTimeTicks = _timeProvider.GetUtcNow().Ticks + _refillIntervalTicks;
}
///
/// Computes the number of new tokens made available to the bucket for consumption by determining the
/// number of time intervals that have passed and multiplying by the number of tokens to refill for
/// each time interval.
///
public long Refill()
{
lock (_sync)
{
var currentTimeTicks = _timeProvider.GetUtcNow().Ticks;
if (currentTimeTicks < _nextRefillTimeTicks)
{
return 0L;
}
// determine number of time increments that have passed
var deltaTimeTicks = currentTimeTicks - _nextRefillTimeTicks;
var intervalsElapsed = 1 + Math.Max(deltaTimeTicks / _refillIntervalTicks, 0);
// update next refill time as quantized via the number of passed intervals
_nextRefillTimeTicks += _refillIntervalTicks * intervalsElapsed;
// refill by the tokens per interval times the number of intervals elapsed
return _refillAmount * intervalsElapsed;
}
}
}
}