diff --git a/mtgban/arbit.go b/mtgban/arbit.go index 2e5ee44e..ccaebe51 100644 --- a/mtgban/arbit.go +++ b/mtgban/arbit.go @@ -1,6 +1,7 @@ package mtgban import ( + "math" "strconv" "strings" @@ -72,6 +73,10 @@ type ArbitOpts struct { // It returns a custom factor to be applied on the buylist price, // and whether the entry shoul be skipped CustomCardFilter func(co *mtgmatcher.CardObject) (float64, bool) + + // Constant used to offset prices (the higher the value, the less impactful + // lower prices will be) + ProfitabilityConstant float64 } type ArbitEntry struct { @@ -98,6 +103,10 @@ type ArbitEntry struct { // Amount of cards that can be applied Quantity int + + // The higher the number the better the arbit is. Using this formula + // Profitability Index (PI) = (Difference / (Sell Price + 10)) * log(1 + Spread) * sqrt(Units) + Profitability float64 } func Arbit(opts *ArbitOpts, vendor Vendor, seller Seller) (result []ArbitEntry, err error) { @@ -105,6 +114,7 @@ func Arbit(opts *ArbitOpts, vendor Vendor, seller Seller) (result []ArbitEntry, minSpread := 0.0 useTrades := false rate := 1.0 + profitabilityConstant := 10.0 minPrice := 0.0 minBuyPrice := 0.0 @@ -134,6 +144,9 @@ func Arbit(opts *ArbitOpts, vendor Vendor, seller Seller) (result []ArbitEntry, if opts.Rate != 0 { rate = opts.Rate } + if opts.ProfitabilityConstant > 0 { + profitabilityConstant = opts.ProfitabilityConstant + } useTrades = opts.UseTrades minPrice = opts.MinPrice @@ -306,6 +319,11 @@ func Arbit(opts *ArbitOpts, vendor Vendor, seller Seller) (result []ArbitEntry, } } + profitability := (difference / (price + profitabilityConstant)) * math.Log(1+spread) + if qty > 1 { + profitability *= math.Sqrt(float64(qty)) + } + res := ArbitEntry{ CardId: cardId, BuylistEntry: blEntry, @@ -314,6 +332,7 @@ func Arbit(opts *ArbitOpts, vendor Vendor, seller Seller) (result []ArbitEntry, AbsoluteDifference: difference * float64(qty), Spread: spread, Quantity: qty, + Profitability: profitability, } result = append(result, res) } @@ -417,6 +436,7 @@ func Mismatch(opts *ArbitOpts, reference Seller, probe Seller) (result []ArbitEn maxSpread := 0.0 minPrice := 0.0 minQty := 0 + profitabilityConstant := 10.0 filterFoil := false filterOnlyFoil := false filterRLOnly := false @@ -434,6 +454,9 @@ func Mismatch(opts *ArbitOpts, reference Seller, probe Seller) (result []ArbitEn if opts.MinSpread != 0 { minSpread = opts.MinSpread } + if opts.ProfitabilityConstant > 0 { + profitabilityConstant = opts.ProfitabilityConstant + } minPrice = opts.MinPrice maxSpread = opts.MaxSpread @@ -559,6 +582,11 @@ func Mismatch(opts *ArbitOpts, reference Seller, probe Seller) (result []ArbitEn } } + profitability := (difference / (price + profitabilityConstant)) * math.Log(1+spread) + if qty > 1 { + profitability *= math.Sqrt(float64(qty)) + } + res := ArbitEntry{ CardId: cardId, InventoryEntry: invEntry, @@ -566,6 +594,7 @@ func Mismatch(opts *ArbitOpts, reference Seller, probe Seller) (result []ArbitEn Difference: difference, Spread: spread, Quantity: qty, + Profitability: profitability, } result = append(result, res) } diff --git a/mtgban/csv.go b/mtgban/csv.go index cd282624..52aa14b4 100644 --- a/mtgban/csv.go +++ b/mtgban/csv.go @@ -28,7 +28,7 @@ var ( // The canonical header that will be present in all buylist files BuylistHeader = append(CardHeader, "Conditions", "Buy Price", "Trade Price", "Quantity", "Price Ratio", "URL", "Vendor") - ArbitHeader = append(CardHeader, "Conditions", "Available", "Sell Price", "Buy Price", "Trade Price", "Difference", "Spread", "Abs Difference", "Price Ratio") + ArbitHeader = append(CardHeader, "Conditions", "Available", "Sell Price", "Buy Price", "Trade Price", "Difference", "Spread", "Abs Difference", "Profitability") MismatchHeader = append(CardHeader, "Conditions", "Price", "Reference", "Difference", "Spread") @@ -463,7 +463,7 @@ func WriteArbitrageToCSV(arbitrage []ArbitEntry, w io.Writer) error { fmt.Sprintf("%0.2f", entry.Difference), fmt.Sprintf("%0.2f", entry.Spread), fmt.Sprintf("%0.2f", entry.AbsoluteDifference), - fmt.Sprintf("%0.2f", bl.PriceRatio), + fmt.Sprintf("%0.2f", entry.Profitability), ) if hasExtraSeller { record = append(record, inv.SellerName)