Updates market averages

This commit is contained in:
Ben 2024-04-22 14:27:09 +02:00
parent d3390892af
commit 2f6256756a
No known key found for this signature in database
GPG Key ID: 541B9D8C9F1426A1
4 changed files with 49 additions and 89 deletions

View File

@ -15,8 +15,7 @@
public class MarketAverage public class MarketAverage
{ {
public int NumberOfFinished { get; set; } public string Title { get; set; } = string.Empty;
public int TimeRangeSeconds { get; set; }
public float Price { get; set; } public float Price { get; set; }
public float Size { get; set; } public float Size { get; set; }
public float Duration { get; set; } public float Duration { get; set; }

View File

@ -1,7 +1,6 @@
using BiblioTech.Options; using BiblioTech.Options;
using DiscordRewards; using DiscordRewards;
using System.Globalization; using System.Globalization;
using Utils;
namespace BiblioTech.Commands namespace BiblioTech.Commands
{ {
@ -31,13 +30,7 @@ namespace BiblioTech.Commands
private string[] GetInsight(MarketAverage avg) private string[] GetInsight(MarketAverage avg)
{ {
var timeRange = TimeSpan.FromSeconds(avg.TimeRangeSeconds); var headerLine = $"[{avg.Title}]";
var headerLine = $"[Last {Time.FormatDuration(timeRange)}] ({avg.NumberOfFinished} Contracts finished)";
if (avg.NumberOfFinished == 0)
{
return new[] { headerLine };
}
return new[] return new[]
{ {

View File

@ -19,9 +19,6 @@ namespace TestNetRewarder
[Uniform("check-history", "ch", "CHECKHISTORY", true, "Unix epoc timestamp of a moment in history on which processing begins. Required for hosting rewards. Should be 'launch of the testnet'.")] [Uniform("check-history", "ch", "CHECKHISTORY", true, "Unix epoc timestamp of a moment in history on which processing begins. Required for hosting rewards. Should be 'launch of the testnet'.")]
public int CheckHistoryTimestamp { get; set; } = 0; public int CheckHistoryTimestamp { get; set; } = 0;
[Uniform("market-insights", "mi", "MARKETINSIGHTS", false, "Semi-colon separated integers. Each represents a multiple of intervals, for which a market insights average will be generated.")]
public string MarketInsights { get; set; } = "1;96";
[Uniform("events-overview", "eo", "EVENTSOVERVIEW", false, "When greater than zero, chain event summary will be generated. (default 1)")] [Uniform("events-overview", "eo", "EVENTSOVERVIEW", false, "When greater than zero, chain event summary will be generated. (default 1)")]
public int CreateChainEventsOverview { get; set; } = 1; public int CreateChainEventsOverview { get; set; } = 1;

View File

@ -6,66 +6,47 @@ namespace TestNetRewarder
{ {
public class MarketTracker public class MarketTracker
{ {
private readonly List<ChainState> buffer = new List<ChainState>(); private readonly MarketAverage MostRecent = new MarketAverage
{
Title = "Most recent"
};
private readonly MarketAverage Irf = new MarketAverage
{
Title = "Recent average"
};
public MarketAverage[] ProcessChainState(ChainState chainState) public MarketAverage[] ProcessChainState(ChainState chainState)
{ {
var intervalCounts = GetInsightCounts(); UpdateMostRecent(chainState);
if (!intervalCounts.Any()) return Array.Empty<MarketAverage>(); UpdateIrf(chainState);
UpdateBuffer(chainState, intervalCounts.Max()); return new[]
var result = intervalCounts
.Select(GenerateMarketAverage)
.Where(a => a != null)
.Cast<MarketAverage>()
.ToArray();
if (!result.Any()) result = Array.Empty<MarketAverage>();
return result;
}
private void UpdateBuffer(ChainState chainState, int maxNumberOfIntervals)
{ {
buffer.Add(chainState); MostRecent,
while (buffer.Count > maxNumberOfIntervals) Irf
{
buffer.RemoveAt(0);
}
}
private MarketAverage? GenerateMarketAverage(int numberOfIntervals)
{
var states = SelectStates(numberOfIntervals);
return CreateAverage(states);
}
private ChainState[] SelectStates(int numberOfIntervals)
{
if (numberOfIntervals < 1) return Array.Empty<ChainState>();
if (numberOfIntervals > buffer.Count) return Array.Empty<ChainState>();
return buffer.TakeLast(numberOfIntervals).ToArray();
}
private MarketAverage? CreateAverage(ChainState[] states)
{
try
{
return new MarketAverage
{
NumberOfFinished = CountNumberOfFinishedRequests(states),
TimeRangeSeconds = GetTotalTimeRange(states),
Price = Average(states, s => s.Request.Ask.Reward),
Duration = Average(states, s => s.Request.Ask.Duration),
Size = Average(states, s => GetTotalSize(s.Request.Ask)),
Collateral = Average(states, s => s.Request.Ask.Collateral),
ProofProbability = Average(states, s => s.Request.Ask.ProofProbability)
}; };
} }
catch (Exception ex)
private void UpdateIrf(ChainState chainState)
{ {
Program.Log.Error($"Exception in CreateAverage: {ex}"); if (!chainState.FinishedRequests.Any()) return;
return null;
MostRecent.Price = GetIrf(MostRecent.Price, chainState, s => s.Request.Ask.Reward);
MostRecent.Duration = GetIrf(MostRecent.Duration, chainState, s => s.Request.Ask.Duration);
MostRecent.Size = GetIrf(MostRecent.Size, chainState, s => GetTotalSize(s.Request.Ask));
MostRecent.Collateral = GetIrf(MostRecent.Collateral, chainState, s => s.Request.Ask.Collateral);
MostRecent.ProofProbability = GetIrf(MostRecent.ProofProbability, chainState, s => s.Request.Ask.ProofProbability);
} }
private void UpdateMostRecent(ChainState chainState)
{
if (!chainState.FinishedRequests.Any()) return;
MostRecent.Price = Average(chainState, s => s.Request.Ask.Reward);
MostRecent.Duration = Average(chainState, s => s.Request.Ask.Duration);
MostRecent.Size = Average(chainState, s => GetTotalSize(s.Request.Ask));
MostRecent.Collateral = Average(chainState, s => s.Request.Ask.Collateral);
MostRecent.ProofProbability = Average(chainState, s => s.Request.Ask.ProofProbability);
} }
private int GetTotalSize(Ask ask) private int GetTotalSize(Ask ask)
@ -75,50 +56,40 @@ namespace TestNetRewarder
return nSlots * slotSize; return nSlots * slotSize;
} }
private float Average(ChainState[] states, Func<StorageRequest, BigInteger> getValue) private float Average(ChainState state, Func<StorageRequest, BigInteger> getValue)
{ {
return Average(states, s => Convert.ToInt32(getValue(s))); return Average(state, s => Convert.ToInt32(getValue(s)));
} }
private float Average(ChainState[] states, Func<StorageRequest, int> getValue) private float GetIrf(float current, ChainState state, Func<StorageRequest, BigInteger> getValue)
{
return GetIrf(current, state, s => Convert.ToInt32(getValue(s)));
}
private float Average(ChainState state, Func<StorageRequest, int> getValue)
{ {
var sum = 0.0f; var sum = 0.0f;
var count = 0.0f; var count = 0.0f;
foreach (var state in states)
{
foreach (var finishedRequest in state.FinishedRequests) foreach (var finishedRequest in state.FinishedRequests)
{ {
sum += getValue(finishedRequest); sum += getValue(finishedRequest);
count++; count++;
} }
}
if (count < 1.0f) return 0.0f; if (count < 1.0f) return 0.0f;
return sum / count; return sum / count;
} }
private int GetTotalTimeRange(ChainState[] states) private float GetIrf(float current, ChainState state, Func<StorageRequest, int> getValue)
{ {
return Convert.ToInt32((Program.Config.Interval * states.Length).TotalSeconds); var result = current;
foreach (var finishedRequest in state.FinishedRequests)
{
float v = getValue(finishedRequest);
result = (result + v) / 2.0f;
} }
private int CountNumberOfFinishedRequests(ChainState[] states) return result;
{
return states.Sum(s => s.FinishedRequests.Length);
}
private int[] GetInsightCounts()
{
try
{
var tokens = Program.Config.MarketInsights.Split(';').ToArray();
return tokens.Select(t => Convert.ToInt32(t)).ToArray();
}
catch (Exception ex)
{
Program.Log.Error($"Exception when parsing MarketInsights config parameters: {ex}");
}
return Array.Empty<int>();
} }
} }
} }