Класс для загрузки, проверки и поставки конфигурации данных .файл py


Вызываемый класс ниже конфигурации загружает данные, форматирует их в форму, совместимую с моим приложением(от человека-версия), выполняет некоторые важные проверки, и, наконец, делает его доступным осуществляться путем вызова экземпляра.

Это часть моей(рабочей) на финансовых рынках приложения, написанные после 10 месяцев заочная программирования. Я пытаюсь решить это много, много конструктивных недостатков. Один-на-один.

В BotOrderData класс является частью моей попытке перенести все данные конфигурации из исходного кода в одной конфигурации местоположение. Таким образом, требование для нескольких из этих видов классов(или то, что заканчивается самое лучшее решение). Например, мне часто требуется менять такие параметры, как:

  • ценообразование
  • волатильность рынка допуски
  • время, в котором приложение должно воздержаться от торговли

Я хотел бы знать, если это грамотный выбор конструкции, любые варианты, и любые другие мелкие рефакторинги.

Код:

class BotOrderData():
    """A class for loading, formatting, checking, storing ``Bot`` pricing data

    The BotOrderData class wraps a dict which holds the various pricing
    parameters after loading, formatting and checking functions are performed.
    This data is accessed by instance of ``Bot``.

    :ivar DEFAULT_PARAMS: a dict of human-friendly pricing configuration data
    to be used in the absence of local configuration file data.
    """
    #
    # TO DO:
    # Finish docstrings
    #
    # The default bot pricing data, should none be available from a local
    # config file listed in self.config_locations

    DEFAULT_PARAMS = {
        "S": {"EUR_USD": {"trigger":   1.2, "upper":  2.0, "ignore": 4.999},
              "GBP_USD": {"trigger":   1.2, "upper":  2.0, "ignore": 4.999},
              "EUR_GBP": {"trigger":   1.2, "upper":  2.0, "ignore": 4.999},
              },
        "B": {"EUR_USD": {"trigger":   0.0, "upper": -2.0, "ignore": 4.999},
              "GBP_USD": {"trigger":   0.0, "upper": -2.0, "ignore": 4.999},
              "EUR_GBP": {"trigger":   0.0, "upper": -2.0, "ignore": 4.999},
              }
        }

    def __init__(self):
        """Initialize the Triggers object

        :ivar params: a dict which holds the bot order parameters
        :ivar config_name: a str. The basename of the config file to search the
        system for.
        :ivar config_locations: an iterable of folders locations which may
        contain a qualifying config file. To be listed in the order in which
        they should take precendence. Eg; that listed first takes priority
        """
        self.params = dict()
        self.config_name = "bot_config_data.py"

        # List locations in order of highest priority first. Eg; if the
        # first location exists, it's data will be loaded and used for
        # configuration
        self.config_locations = (
            r"C:\Users\Dave\Bot",
            os.path.expanduser("~trade_bot/"),
            )
        self.add_param_data()

    def __call__(self, action: str, mkt_id: str):
        """Query and return pricing parameter data

        :returns: A tuple of three float values in order
        ("trigger", "upper", "ignore")
        """
        return (self.params[action][mkt_id]["trigger"],
                self.params[action][mkt_id]["upper"],
                self.params[action][mkt_id]["ignore"],
                )

    def discover_locations(self):
        """Return a list of configuration file locations"""
        logging.debug("self.config_locations: {}".format(self.config_locations))
        locations = [os.path.join(path, self.config_name)
                     for path in self.config_locations]
        exist = [l for l in locations if os.path.exists(l)]      
        return exist

    def get_config_from_file(self):
        """Load data from the first configuration file in available locations
        """
        data = {}
        locations = self.discover_locations()
        if not locations:
            return None
        with open(locations[0]) as f:
            code = compile(f.read(), locations[0], "exec")
        exec(code, globals(), data)
        return data["price_data"]

    def process_params(self, params: dict):
        """Convert the human-friendly config data -> ``Bot`` friendly version

        :param: params: a dict of config data, either from a local config file
        or from DEFAULT_PARAMS if the former is not present
        """
        sell_mkt = params["S"]
        buy_mkt = params["B"]

        for s_mkt in sell_mkt:
            sell_mkt[s_mkt]["trigger"] = 1.0 + sell_mkt[s_mkt]["trigger"]/100
            sell_mkt[s_mkt]["upper"] = 1.0 + sell_mkt[s_mkt]["upper"]/100
        for b_mkt in buy_mkt:
            buy_mkt[b_mkt]["trigger"] = 1.0 + buy_mkt[b_mkt]["trigger"]/100
            buy_mkt[b_mkt]["upper"] = 1.0 + buy_mkt[b_mkt]["upper"]/100
        return params

    def add_param_data(self):
        """Manager method which adds pricing parameters to self.params"""
        file_config = self.get_config_from_file()
        params = self.DEFAULT_PARAMS if not file_config else file_config
        params = self.process_params(params)
        self.check_params(params)
        self.params.update(params)

    def check_params(self, params: dict):
        """Check the params data is valid. This check must ALWAYS pass.

        :param params: a nested dict of Bot pricing parameters 
        """
        checks = list(
            [e for e in params["B"] if params["B"][e]["trigger"] > 1.00
             or params["B"][e]["upper"] > params["B"][e]["trigger"]
             or params["B"][e]["ignore"] < 0]
            +
            [e for e in params["S"] if params["S"][e]["trigger"] < 1.00
             or params["S"][e]["upper"] < params["S"][e]["trigger"]
             or params["S"][e]["ignore"] < 0]
            )
        assert not checks, (self.__class__.__name__
                            + " contains invalid data: {}".format(params))
bot_pricing_data = BotOrderData()  # module level variable

Пример использования:

from bot_prices import bot_pricing_data

class Bot():
    def __init__():
        self.trigger, self.upper, self.ignore =\
         bot_pricing_data(self.action , self.mkt_id)  # eg ("B", "EUR_USD")


120
4
задан 28 февраля 2018 в 01:02 Источник Поделиться
Комментарии
1 ответ

упадет тебе пару соображений

Вы можете сохранять параметры по умолчанию на отдельном файле настроек, или еще лучше, на YAML файл, который поможет вам в решении задач, читать и изменять эту настройку, вы или кто-то без особых знаний в Python.

Более подробную информацию о том, как интегрировать конфигурации в YAML в языке Python проекта: https://pyyaml.org/wiki/PyYAMLDocumentation

self.config_locations вы наверняка хотите, чтобы извлечь на файл настройки, так как в будущем это может измениться, когда вы запустите программу на другом компьютере, тогда вам просто загрузить эти настройки из любого места с разными путями.

add_param_data может быть переименован в load_configurationили load_settings, которая является более явной, что происходит. А в идеале логика, чтобы понять, где параметры идут из вне, и вызвать этот метод с параметром, который будет путь к параметрам по умолчанию (файл или дикт или YAML..)

check_params и process_params повторил код, вы можете просто функция, где вы выполнить тот же код в зависимости от параметров

вместо:

    sell_mkt = params["S"]
buy_mkt = params["B"]

for s_mkt in sell_mkt:
sell_mkt[s_mkt]["trigger"] = 1.0 + sell_mkt[s_mkt]["trigger"]/100
sell_mkt[s_mkt]["upper"] = 1.0 + sell_mkt[s_mkt]["upper"]/100
for b_mkt in buy_mkt:
buy_mkt[b_mkt]["trigger"] = 1.0 + buy_mkt[b_mkt]["trigger"]/100
buy_mkt[b_mkt]["upper"] = 1.0 + buy_mkt[b_mkt]["upper"]/100

Вы могли бы

sell_market = params["S"]
_update_market(sell_market)

Затем в другой способ

def _update_market(market):
for m in market:
market[m]["trigger"] = 1.0 + market[m]["trigger"]/100
market[m]["upper"] = 1.0 + market[m]["upper"]/100

Также, на мой взгляд, discover_locations должен быть переименован в get_location_list

Просто до конца, это, как вы можете создать __init__ метод. Просто идея

def __init__():
file = get_configuration_file()
params = load_parameters(file)
validate_parameters(params) # This will be check_params, that in the end can update self.params

Надеюсь, что вы сделать некоторые обоснованные замечания от всего этого

Наслаждайтесь кодирования!

1
ответ дан 28 февраля 2018 в 10:02 Источник Поделиться