mtgban

package
v0.0.0-...-462b367 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 23, 2024 License: MIT Imports: 16 Imported by: 4

Documentation

Overview

Package mtgban defines interfaces for scrapers and utility functions to obtain pricing information from various vendors.

Index

Constants

View Source
const (
	DefaultArbitMinDiff      = 0.2
	DefaultArbitMinSpread    = 25.0
	DefaultMultiMinDiff      = 5.0
	DefaultMultiMinSpread    = 100.0
	DefaultMismatchMinDiff   = 1.0
	DefaultMismatchMinSpread = 100.0
)

Variables

View Source
var (
	// The base Card fields for the canonical headers
	CardHeader = []string{
		"Key", "Name", "Edition", "Finish", "Number", "Rarity",
	}

	// The canonical header that will be present in all inventory files
	InventoryHeader = append(CardHeader, "Conditions", "Price", "Quantity", "URL")

	// The canonical header that will be present in all market files
	MarketHeader = append(InventoryHeader, "Seller", "Bundle")

	// Additional fields for Markets neecessary for Carters
	CartHeader = append(MarketHeader, "Original Id", "Instance Id")

	// 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")

	MismatchHeader = append(CardHeader, "Conditions", "Price", "Reference", "Difference", "Spread")

	MultiArbitHeader = []string{
		"Seller", "Cards", "Listings", "Total Prices", "Total Buylist", "Difference", "Spread",
	}

	MarketTotalsHeader = append(CardHeader, "Listings", "Total Quantity", "Lowest Price", "Average", "Spread")
)
View Source
var DefaultGradeTags = []string{
	"NM", "SP", "MP", "HP",
}

The default list of conditions most scrapers output

View Source
var ErrScraperNotFound = errors.New("scraper not found")
View Source
var FullGradeTags = []string{
	"NM", "SP", "MP", "HP", "PO",
}

The full list of conditions supported

Functions

func DateEqual

func DateEqual(date1, date2 time.Time) bool

func GetExchangeRate

func GetExchangeRate(currency string) (float64, error)

func WriteArbitrageToCSV

func WriteArbitrageToCSV(arbitrage []ArbitEntry, w io.Writer) error

func WriteBuylistToCSV

func WriteBuylistToCSV(buylist BuylistRecord, w io.Writer) error

func WriteCombineToCSV

func WriteCombineToCSV(root *CombineRoot, w io.Writer) error

func WriteInventoryToCSV

func WriteInventoryToCSV(inventory InventoryRecord, w io.Writer) error

func WriteMismatchToCSV

func WriteMismatchToCSV(mismatch []ArbitEntry, w io.Writer) error

func WriteMultiArbitrageToCSV

func WriteMultiArbitrageToCSV(multi []MultiArbitEntry, w io.Writer) error

func WritePennyToCSV

func WritePennyToCSV(penny []PennystockEntry, w io.Writer) error

func WriteScraperToJSON

func WriteScraperToJSON(scraper Scraper, w io.Writer) error

func WriteSellerToCSV

func WriteSellerToCSV(seller Seller, w io.Writer) error

func WriteSellerToJSON

func WriteSellerToJSON(seller Seller, w io.Writer) error

func WriteTotalsToCSV

func WriteTotalsToCSV(totals []MarketTotalsEntry, w io.Writer) error

func WriteVendorToCSV

func WriteVendorToCSV(vendor Vendor, w io.Writer) error

func WriteVendorToJSON

func WriteVendorToJSON(vendor Vendor, w io.Writer) error

Types

type ArbitEntry

type ArbitEntry struct {
	// ID of the card
	CardId string

	// The buylist used to determine Arbit
	BuylistEntry BuylistEntry

	// The actual entry that matches either of the above
	InventoryEntry InventoryEntry

	// The inventory used to determine Mismatch
	ReferenceEntry InventoryEntry

	// Difference of the prices
	Difference float64

	// Spread between the the prices
	Spread float64

	// Difference of the prices accounting for quantities available
	AbsoluteDifference float64

	// Amount of cards that can be applied
	Quantity int
}

func Arbit

func Arbit(opts *ArbitOpts, vendor Vendor, seller Seller) (result []ArbitEntry, err error)

func Mismatch

func Mismatch(opts *ArbitOpts, reference Seller, probe Seller) (result []ArbitEntry, err error)

type ArbitOpts

type ArbitOpts struct {
	// Extra factor to modify Inventory prices
	Rate float64

	// Minimum Inventory price
	MinPrice float64

	// Minimum Buylist price
	MinBuyPrice float64

	// Minimum difference between prices
	MinDiff float64

	// Minimum Inventory quantities
	MinQuantity int

	// Minimum spread % between prices
	MinSpread float64

	// Maximum Spread % between prices
	MaxSpread float64

	// Maximum price ratio of Inventory
	MaxPriceRatio float64

	// Use credit for Buylist prices
	UseTrades bool

	// Whether to consider foils
	NoFoil   bool
	OnlyFoil bool

	// Whether to skip non-rl cards
	OnlyReserveList bool

	// List of conditions to ignore
	Conditions []string

	// List of rarities to ignore
	Rarities []string

	// List of editions to ignore
	Editions []string

	// List of editions to select
	OnlyEditions []string

	// List of per-edition collector numbers to select
	OnlyCollectorNumberRanges map[string][2]int

	// Only run for products with static decklists
	SealedDecklist bool

	// Only select entries which are part of a bundle
	OnlyBundles bool

	// List of seller name that wil be considered
	Sellers []string

	// Custom function to be run on the card
	// 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)
}

type BanClient

type BanClient struct {
	// contains filtered or unexported fields
}

BanClient abstracts some common operations that can be performed on any Scraper type types, as well as offering a way to retrieve a single or multiple Scapers.

func NewClient

func NewClient() *BanClient

Return an empty BanClient

func (*BanClient) Load

func (bc *BanClient) Load() error

Load inventory and buylist content for each scraper registered in the client

func (*BanClient) Markets

func (bc *BanClient) Markets() (markets []Market)

Return a new slice containing all the markets registered in the client

func (*BanClient) Register

func (bc *BanClient) Register(scraper Scraper)

Add a Scraper to the client

func (*BanClient) RegisterSeller

func (bc *BanClient) RegisterSeller(scraper Scraper)

Add a Scraper to the client, enable the seller side only (if any)

func (*BanClient) RegisterVendor

func (bc *BanClient) RegisterVendor(scraper Scraper)

Add a Scraper to the client, enable the vendor side only (if any)

func (*BanClient) ScraperByName

func (bc *BanClient) ScraperByName(shorthand string) (Scraper, error)

Return the scraper with a matching name from the ones registered in the client

func (*BanClient) Scrapers

func (bc *BanClient) Scrapers() (scrapers []Scraper)

Return a new slice containing all the scrapers registered in the client

func (*BanClient) Sellers

func (bc *BanClient) Sellers() (sellers []Seller)

Return a new slice containing all the sellers registered in the client

func (*BanClient) Vendors

func (bc *BanClient) Vendors() (vendors []Vendor)

Return a new slice containing all the vendors registered in the client

type BaseSeller

type BaseSeller struct {
	// contains filtered or unexported fields
}

func (*BaseSeller) Info

func (seller *BaseSeller) Info() ScraperInfo

func (*BaseSeller) Inventory

func (seller *BaseSeller) Inventory() (InventoryRecord, error)

type BaseVendor

type BaseVendor struct {
	// contains filtered or unexported fields
}

func (*BaseVendor) Buylist

func (vendor *BaseVendor) Buylist() (BuylistRecord, error)

func (*BaseVendor) Info

func (vendor *BaseVendor) Info() (info ScraperInfo)

type BuylistEntry

type BuylistEntry struct {
	// Quantity of this entry
	Quantity int `json:"quantity"`

	// The grade of the current entry
	// Only supported values are listed in FullGradeTags
	// If empty it is considered "NM".
	Conditions string `json:"conditions"`

	// The price at which this entry is bought, in USD
	BuyPrice float64 `json:"buy_price"`

	// The price at which this entry is bought, in store credit
	TradePrice float64 `json:"trade_price,omitempty"`

	// The ratio between the sale and buy prices, indicating desiderability
	// of the entry by the provider
	PriceRatio float64 `json:"price_ratio,omitempty"`

	// The link for this entry on the scraper website (if available)
	URL string `json:"url"`

	// Name of the vendor providing the entry
	VendorName string `json:"vendor_name,omitempty"`

	// Original identifier as available from the scraper
	OriginalId string `json:"original_id,omitempty"`

	// Any additional custom fields set by the scraper
	CustomFields map[string]string `json:"custom_fields,omitempty"`

	// SKU id, composed of ScryfallId, language, finish, and condition
	SKUID string `json:"sku_id,omitempty"`
}

BuylistEntry represents an entry for buying a particular Card

func (BuylistEntry) Condition

func (be BuylistEntry) Condition() string

func (BuylistEntry) Pricing

func (be BuylistEntry) Pricing() float64

type BuylistInitializer

type BuylistInitializer interface {
	// Initialize a buylist.
	InitializeBuylist(io.Reader) error
}

BuylistInitializer is the inteface used to identify scrapers that can have buylist data loaded offline.

type BuylistRecord

type BuylistRecord map[string][]BuylistEntry

The base map for Vendor containing a uuid pointing to an array of BuylistEntry

func LoadBuylistFromCSV

func LoadBuylistFromCSV(r io.Reader, flags ...bool) (BuylistRecord, error)

func (BuylistRecord) Add

func (bl BuylistRecord) Add(cardId string, entry *BuylistEntry) error

func (BuylistRecord) AddRelaxed

func (bl BuylistRecord) AddRelaxed(cardId string, entry *BuylistEntry) error

type Carter

type Carter interface {
	// Enable the cart interface (loading the existing cart for example).
	Activate(user, pass string) error

	// Add an InventoryEntry to the online cart.
	Add(entry InventoryEntry) error
}

Carter is the inteface used to identify Seller scrapers that can add entries to the online cart of the provider.

type CombineEntry

type CombineEntry struct {
	ScraperName string
	Price       float64
	Ratio       float64
	Quantity    int
	URL         string
}

type CombineRoot

type CombineRoot struct {
	Names   []string
	Entries map[string]map[string]CombineEntry
}

func CombineBuylists

func CombineBuylists(vendors []Vendor, useCredit bool) (*CombineRoot, error)

func CombineInventories

func CombineInventories(sellers []Seller) (*CombineRoot, error)

type GenericEntry

type GenericEntry interface {
	Pricing() float64
	Condition() string
}

Interface describing common operations on entries

type InventoryEntry

type InventoryEntry struct {
	// Quantity of this entry
	Quantity int `json:"quantity"`

	// The grade of the current entry
	// Only supported values are listed in FullGradeTags
	Conditions string `json:"conditions"`

	// The price of this entry, in USD
	Price float64 `json:"price"`

	// The link for this entry on the scraper website (if available)
	URL string `json:"url"`

	// Only used for a Marketplace inventory
	SellerName string `json:"seller_name,omitempty"`

	// Part of a hub of sellers that can ship directly
	Bundle bool `json:"bundle,omitempty"`

	// Original identifier as available from the scraper
	// This is usually the "product id".
	OriginalId string `json:"original_id,omitempty"`

	// Original instance identifier as available from the scraper
	// This is usually the "SKU", or the id of the entry taking into
	// account different properties, such as conditions, language etc
	InstanceId string `json:"instance_id,omitempty"`

	// Any additional custom fields set by the scraper
	CustomFields map[string]string `json:"custom_fields,omitempty"`

	// SKU id, composed of ScryfallId, language, finish, and condition
	SKUID string `json:"sku_id,omitempty"`
}

InventoryEntry represents an entry for selling a particular Card

func (InventoryEntry) Condition

func (ie InventoryEntry) Condition() string

func (InventoryEntry) Pricing

func (ie InventoryEntry) Pricing() float64

type InventoryInitializer

type InventoryInitializer interface {
	// Initialize an inventory.
	InitializeInventory(io.Reader) error
}

InventoryInitializer is the inteface used to identify scrapers that can have inventory data loaded offline.

type InventoryRecord

type InventoryRecord map[string][]InventoryEntry

The base map for Seller containing a uuid pointing to an array of InventoryEntry

func LoadInventoryFromCSV

func LoadInventoryFromCSV(r io.Reader, flags ...bool) (InventoryRecord, error)

func LoadMarketFromCSV

func LoadMarketFromCSV(r io.Reader, flags ...bool) (map[string]InventoryRecord, InventoryRecord, error)

func (InventoryRecord) Add

func (inv InventoryRecord) Add(cardId string, entry *InventoryEntry) error

Add a new record to the inventory, similar existing entries are merged

func (InventoryRecord) AddRelaxed

func (inv InventoryRecord) AddRelaxed(cardId string, entry *InventoryEntry) error

Add a new record to the inventory, existing entries are always merged

func (InventoryRecord) AddStrict

func (inv InventoryRecord) AddStrict(cardId string, entry *InventoryEntry) error

Add new record to the inventory, similar existing entries are not merged

func (InventoryRecord) AddUnique

func (inv InventoryRecord) AddUnique(cardId string, entry *InventoryEntry) error

Add new record to the inventory, if same card and condition exist, error out

type LogCallbackFunc

type LogCallbackFunc func(format string, a ...interface{})

type Market

type Market interface {
	// Return the whole inventory for a Market. If not already loaded,
	// it will start scraping the seller gathering the necessary data.
	Inventory() (InventoryRecord, error)

	// Return the inventory for any given seller present in the market.
	// If possible, it will use the Inventory() call to populate data.
	InventoryForSeller(string) (InventoryRecord, error)

	// Return some information about the market
	Info() ScraperInfo

	// Return all names for the sellers present in the Market
	MarketNames() []string
}

Market is the interface describing actions to be performed on the inventory available on a platform, usually combining different sellers

type MarketTotalsEntry

type MarketTotalsEntry struct {
	CardId string

	SingleListings  int
	TotalQuantities int

	Lowest  float64
	Average float64
	Spread  float64
}

func MarketTotals

func MarketTotals(opts *MarketTotalsOptions, market Market) (result []MarketTotalsEntry, err error)

type MarketTotalsOptions

type MarketTotalsOptions struct {
	FilterFunc func(cardId string) bool
}

type MultiArbitEntry

type MultiArbitEntry struct {
	SellerName string
	VendorName string

	Quantity int
	Entries  []ArbitEntry

	Price        float64
	BuylistPrice float64

	Difference float64
	Spread     float64
}

func MultiArbit

func MultiArbit(opts *MultiArbitOpts, vendor Vendor, market Market) (result []MultiArbitEntry, err error)

type MultiArbitOpts

type MultiArbitOpts struct {
	Options *ArbitOpts
	Extra   float64

	MinDifference float64
	MinSpread     float64
}

type PennystockEntry

type PennystockEntry struct {
	CardId string
	InventoryEntry
}

func Pennystock

func Pennystock(seller Seller, full bool) (result []PennystockEntry, err error)

type Scraper

type Scraper interface {
	Info() ScraperInfo
}

Scraper is the interface both Sellers and Vendors need to implement

type ScraperInfo

type ScraperInfo struct {
	// Full name of the store
	Name string `json:"name"`

	// Shorthand or ID of the store
	Shorthand string `json:"shorthand"`

	// Symbol for worldwide stores
	CountryFlag string `json:"country,omitempty"`

	// Timestamp of the last Inventory() execution
	InventoryTimestamp *time.Time `json:"inventory_ts,omitempty"`

	// Timestamp of the last Buylist() execution
	BuylistTimestamp *time.Time `json:"buylist_ts,omitempty"`

	// Only index-style data is available, no quantities or conditions
	MetadataOnly bool `json:"metadata,omitempty"`

	// Vendor has no store credit bonus
	NoCredit bool `json:"no_credit,omitempty"`

	// Inventory quantities are not available
	NoQuantityInventory bool `json:"no_qty_inventory,omitempty"`

	// Scraper contains sealed information instead of singles
	SealedMode bool `json:"sealed,omitempty"`

	// Any additional custom fields set by the user
	CustomFields map[string]string `json:"custom_fields,omitempty"`
}

ScraperInfo contains

type Seller

type Seller interface {
	// Return the inventory for a Seller. If not already loaded, it will start
	// scraping the seller gathering the necessary data.
	Inventory() (InventoryRecord, error)

	// Return some information about the seller
	Info() ScraperInfo
}

Seller is the interface describing actions to be performed on a seller inventory

func NewSellerFromInventory

func NewSellerFromInventory(inventory InventoryRecord, info ScraperInfo) Seller

func ReadSellerFromJSON

func ReadSellerFromJSON(r io.Reader) (Seller, error)

func Seller2Sellers

func Seller2Sellers(market Market) ([]Seller, error)

Separate a Market into multiple Seller objects

type Vendor

type Vendor interface {
	// Return the buylist for a Vendor. If not already loaded, it will start
	// scraping the vendor gathering the necessary data.
	Buylist() (BuylistRecord, error)

	// Return some information about the vendor
	Info() ScraperInfo
}

Vendor is the interface describing actions to be performed on a vendor buylist

func NewVendorFromBuylist

func NewVendorFromBuylist(buylist BuylistRecord, info ScraperInfo) Vendor

func ReadVendorFromJSON

func ReadVendorFromJSON(r io.Reader) (Vendor, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL