# Path: smarkets/utils.py
# def memoized_by_args(*args):
#     """Create memoization decorator more efficient than one generated by memoized.
# 
#     The downside is default values are not supported and you need to declare the arguments manually.
# 
#     >>> def x(a, b):
#     ...     print('ping')
#     ...     return a + b
#     ...
#     >>> memx = memoized_by_args('a', 'b')(x)
#     >>> memx(1, 2)
#     ping
#     3
#     >>> memx(1, 2)
#     3
#     """
#     cache = {}  # noqa
#     exec_(
#         '''
# def decorator(fun):
#     @functools.wraps(fun)
#     def wrapper(%(args)s, cache=cache, fun=fun):
#         key = (%(args)s)
#         try:
#             return cache[key]
#         except KeyError:
#             value = cache[key] = fun(%(args)s)
#             return value
#     return wrapper''' % dict(args=', '.join(args)),
#         dict(cache=cache, functools=functools), locals())
#     return locals()['decorator']
# 
# def slots_repr(self):
#     """Generates object repr based on object's __slots__.
# 
#     Operates under assumption that __slots__ correspond to object's class' constructor
#     parameters.
#     """
#     return '%s(%s)' % (
#         type(self).__name__,
#         ', '.join('%s=%r' % (key, getattr(self, key)) for key in self.__slots__)
#     )


import bisect
import functools
import re
import six
from decimal import Decimal
from babel.numbers import format_percent
from smarkets.utils import memoized_by_args, slots_repr
        amer = self.american
        return '+%s' % amer if amer > 0 else '%s' % amer

    @classmethod
    def from_american(cls, snap, american):
        if not isinstance(american, Decimal):
            raise Exception("American odds needs to be a Decimal object")
        if american < 0:
            return cls((Decimal(100) / (Decimal(-100) / american + 1)).quantize(QUANT))
        return cls((Decimal(10000) / (american + Decimal(100))).quantize(QUANT))

    @classmethod
    def from_decimal(cls, snap, dec):
        if Decimal(dec) in _DEC_TO_PCT:
            return cls(_DEC_TO_PCT[Decimal(dec)])
        else:
            pct = (ONE_HUNDRED / dec).quantize(QUANT)
            return cls(pct)
        raise ValueError

    @classmethod
    def from_fractional(cls, num, den):
        dec = Decimal(num) / Decimal(den) + Decimal(1)
        return cls((Decimal(100) / dec).quantize(QUANT))

    @classmethod
    def from_percent(cls, snap, percent):
        return cls(percent)



# Path: smarkets/utils.py
# def memoized_by_args(*args):
#     """Create memoization decorator more efficient than one generated by memoized.
# 
#     The downside is default values are not supported and you need to declare the arguments manually.
# 
#     >>> def x(a, b):
#     ...     print('ping')
#     ...     return a + b
#     ...
#     >>> memx = memoized_by_args('a', 'b')(x)
#     >>> memx(1, 2)
#     ping
#     3
#     >>> memx(1, 2)
#     3
#     """
#     cache = {}  # noqa
#     exec_(
#         '''
# def decorator(fun):
#     @functools.wraps(fun)
#     def wrapper(%(args)s, cache=cache, fun=fun):
#         key = (%(args)s)
#         try:
#             return cache[key]
#         except KeyError:
#             value = cache[key] = fun(%(args)s)
#             return value
#     return wrapper''' % dict(args=', '.join(args)),
#         dict(cache=cache, functools=functools), locals())
#     return locals()['decorator']
# 
# def slots_repr(self):
#     """Generates object repr based on object's __slots__.
# 
#     Operates under assumption that __slots__ correspond to object's class' constructor
#     parameters.
#     """
#     return '%s(%s)' % (
#         type(self).__name__,
#         ', '.join('%s=%r' % (key, getattr(self, key)) for key in self.__slots__)
#     )


# Path: smarkets/odds.py
import bisect
import functools
import re
import six
from decimal import Decimal
from babel.numbers import format_percent
from smarkets.utils import memoized_by_args, slots_repr

        amer = self.american
        return '+%s' % amer if amer > 0 else '%s' % amer

    @classmethod
    def from_american(cls, snap, american):
        if not isinstance(american, Decimal):
            raise Exception("American odds needs to be a Decimal object")
        if american < 0:
            return cls((Decimal(100) / (Decimal(-100) / american + 1)).quantize(QUANT))
        return cls((Decimal(10000) / (american + Decimal(100))).quantize(QUANT))

    @classmethod
    def from_decimal(cls, snap, dec):
        if Decimal(dec) in _DEC_TO_PCT:
            return cls(_DEC_TO_PCT[Decimal(dec)])
        else:
            pct = (ONE_HUNDRED / dec).quantize(QUANT)
            return cls(pct)
        raise ValueError

    @classmethod
    def from_fractional(cls, num, den):
        dec = Decimal(num) / Decimal(den) + Decimal(1)
        return cls((Decimal(100) / dec).quantize(QUANT))

    @classmethod
    def from_percent(cls, snap, percent):
        return cls(percent)



snap_to_decimal_move_out_by = memoized_by_args('side', 'odds', 'move_out_by')(