Can solve inverse of currency pair

This commit is contained in:
nicolas.dorier 2018-05-05 00:40:54 +09:00
parent 8a4da361fd
commit c2dad08fef
4 changed files with 29 additions and 12 deletions

View File

@ -113,12 +113,21 @@ namespace BTCPayServer.Tests
builder.AppendLine("DOGE_BTC = 2000"); builder.AppendLine("DOGE_BTC = 2000");
Assert.True(RateRules.TryParse(builder.ToString(), out rules)); Assert.True(RateRules.TryParse(builder.ToString(), out rules));
rules.GlobalMultiplier = 1.1m; rules.GlobalMultiplier = 1.1m;
rule2 = rules.GetRuleFor(CurrencyPair.Parse("DOGE_USD")); rule2 = rules.GetRuleFor(CurrencyPair.Parse("DOGE_USD"));
Assert.Equal("(2000 * (-3 + coinbase(BTC_CAD) + 50 - 5)) * 1.1", rule2.ToString()); Assert.Equal("(2000 * (-3 + coinbase(BTC_CAD) + 50 - 5)) * 1.1", rule2.ToString());
rule2.ExchangeRates.SetRate("coinbase", CurrencyPair.Parse("BTC_CAD"), 1000m); rule2.ExchangeRates.SetRate("coinbase", CurrencyPair.Parse("BTC_CAD"), 1000m);
Assert.True(rule2.Reevaluate()); Assert.True(rule2.Reevaluate());
Assert.Equal("(2000 * (-3 + 1000 + 50 - 5)) * 1.1", rule2.ToString(true)); Assert.Equal("(2000 * (-3 + 1000 + 50 - 5)) * 1.1", rule2.ToString(true));
Assert.Equal((2000m * (-3m + 1000m + 50m - 5m)) * 1.1m, rule2.Value.Value); Assert.Equal((2000m * (-3m + 1000m + 50m - 5m)) * 1.1m, rule2.Value.Value);
// Test inverse
rule2 = rules.GetRuleFor(CurrencyPair.Parse("USD_DOGE"));
Assert.Equal("(1 / (2000 * (-3 + coinbase(BTC_CAD) + 50 - 5))) * 1.1", rule2.ToString());
rule2.ExchangeRates.SetRate("coinbase", CurrencyPair.Parse("BTC_CAD"), 1000m);
Assert.True(rule2.Reevaluate());
Assert.Equal("(1 / (2000 * (-3 + 1000 + 50 - 5))) * 1.1", rule2.ToString(true));
Assert.Equal(( 1.0m / (2000m * (-3m + 1000m + 50m - 5m))) * 1.1m, rule2.Value.Value);
//////// ////////
} }
} }

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
<Version>1.0.2.2</Version> <Version>1.0.2.3</Version>
<NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208</NoWarn> <NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -90,5 +90,10 @@ namespace BTCPayServer.Rating
{ {
return $"{Left}_{Right}"; return $"{Left}_{Right}";
} }
public CurrencyPair Inverse()
{
return new CurrencyPair(Right, Left);
}
} }
} }

View File

@ -133,7 +133,6 @@ namespace BTCPayServer.Rating
if (currencyPair.Left == "X" || currencyPair.Right == "X") if (currencyPair.Left == "X" || currencyPair.Right == "X")
throw new ArgumentException(paramName: nameof(currencyPair), message: "Invalid X currency"); throw new ArgumentException(paramName: nameof(currencyPair), message: "Invalid X currency");
var candidate = FindBestCandidate(currencyPair); var candidate = FindBestCandidate(currencyPair);
if (GlobalMultiplier != decimal.One) if (GlobalMultiplier != decimal.One)
{ {
candidate = CreateExpression($"({candidate}) * {GlobalMultiplier.ToString(CultureInfo.InvariantCulture)}"); candidate = CreateExpression($"({candidate}) * {GlobalMultiplier.ToString(CultureInfo.InvariantCulture)}");
@ -143,18 +142,21 @@ namespace BTCPayServer.Rating
public ExpressionSyntax FindBestCandidate(CurrencyPair p) public ExpressionSyntax FindBestCandidate(CurrencyPair p)
{ {
var candidates = new List<(CurrencyPair Pair, int Prioriy, ExpressionSyntax Expression)>(); var invP = p.Inverse();
var candidates = new List<(CurrencyPair Pair, int Prioriy, ExpressionSyntax Expression, bool Inverse)>();
foreach (var pair in new[] foreach (var pair in new[]
{ {
(Pair: p, Priority: 0), (Pair: p, Priority: 0, Inverse: false),
(Pair: new CurrencyPair(p.Left, "X"), Priority: 1), (Pair: new CurrencyPair(p.Left, "X"), Priority: 1, Inverse: false),
(Pair: new CurrencyPair("X", p.Right), Priority: 1), (Pair: new CurrencyPair("X", p.Right), Priority: 1, Inverse: false),
(Pair: new CurrencyPair("X", "X"), Priority: 2) (Pair: new CurrencyPair(invP.Left, "X"), Priority: 2, Inverse: true),
(Pair: new CurrencyPair("X", invP.Right), Priority: 2, Inverse: true),
(Pair: new CurrencyPair("X", "X"), Priority: 3, Inverse: false)
}) })
{ {
if (ruleList.ExpressionsByPair.TryGetValue(pair.Pair, out var expression)) if (ruleList.ExpressionsByPair.TryGetValue(pair.Pair, out var expression))
{ {
candidates.Add((pair.Pair, pair.Priority, expression.Expression)); candidates.Add((pair.Pair, pair.Priority, expression.Expression, pair.Inverse));
} }
} }
if (candidates.Count == 0) if (candidates.Count == 0)
@ -163,8 +165,9 @@ namespace BTCPayServer.Rating
.OrderBy(c => c.Prioriy) .OrderBy(c => c.Prioriy)
.ThenBy(c => c.Expression.Span.Start) .ThenBy(c => c.Expression.Span.Start)
.First(); .First();
return best.Inverse
return best.Expression; ? CreateExpression($"1 / {invP}")
: best.Expression;
} }
internal static ExpressionSyntax CreateExpression(string str) internal static ExpressionSyntax CreateExpression(string str)
@ -364,7 +367,7 @@ namespace BTCPayServer.Rating
string _ExchangeName = null; string _ExchangeName = null;
public List<RateRulesErrors> Errors = new List<RateRulesErrors>(); public List<RateRulesErrors> Errors = new List<RateRulesErrors>();
const int MaxNestedCount = 6; const int MaxNestedCount = 8;
public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node)
{ {
if (CurrencyPair.TryParse(node.Identifier.ValueText, out var currentPair)) if (CurrencyPair.TryParse(node.Identifier.ValueText, out var currentPair))