Path: blob/master/ invest-robot-contest_TradingCompetition2022-main/models/TradingModel.py
5925 views
from decimal import Decimal1from models.ModelChecks import ModelChecks2import yfinance as yf3import pandas as pd4from logger.LoggerFactory import LoggerFactory5from logger.BusinessLogger import BusinessLogger678class TradingModel:9""" Main class for developing trading model10"""1112def __init__(self, ticker, config):13self._ticker = ticker14self._config = config15self._prev_price: Decimal = Decimal() # ToDo Change to list of price (history)16self._last_price: Decimal = Decimal()17self._stop_price = None # Calc stop loos price18self._avg_price: Decimal = Decimal() # Avg price of orders (buy)19self._stock_limit: Decimal = Decimal() # Limit for lot20self._possible_lot: int = 0 # Possible lot for buy21self._stock_drop_limit: int = 10 # Percent of drop limit22self._count_in_lot = 023self._check_handler: ModelChecks = ModelChecks()2425# This model IS NOT available only for any type of orders26self._long_available = False27self._short_available = False2829self._long_open_ordered = False30self._long_close_ordered = False3132self._long_open_done = False33self._long_close_done = False3435self._hist_data: pd = None36self._stock_lot_limit = None3738def custom_init(self):39self._generate_check()4041@property42def config(self):43return self._config4445@config.setter46def config(self, config):47self._config = config4849def get_config(self, options):50return self.config.get(section='TradingStrategy', option=options)5152def _check_model(self):53return True5455def _calculate_model(self):56""" Method for calculate model (should be implemented in each models ) """57pass5859def _download_hist_data(self, start_date, end_date):60""" Down load hist data for stock """61# ToDo This data can be loaded few times (To avoid this, it should be stored in dict)62ticker = self._ticker + '.ME'63self._hist_data = yf.download(ticker, start=start_date, end=end_date, interval="1d")6465def _generate_check(self):66""" Add all checks to self._check_handler (class ModelChecks) """67pass6869def _run_checks(self):70""" Run all checks for this model """71for group, check_key, check in self._check_handler:72if check[ModelChecks.IMPL_METHOD]() is True:73self._check_handler.set_ready(group, check_key)7475def _is_all_true_in_group(self, group) -> bool:76""" Is all check in group eq true? Group = OPEN_LONG, CLOSE_LONG, etc. """77is_all_checks_true = False78for check in self._check_handler.checks[group].values():79is_all_checks_true = check[ModelChecks.IS_READY]80if is_all_checks_true is False:81break82return is_all_checks_true8384@property85def is_ready_to_open_long(self) -> bool:86""" Check all specified checks, if all checks is true, it is time to open long order """87if self._long_available is not True:88return False8990# Is it already opened?91if self.is_long_open_done is True:92return False9394# Is it already ordered?95if self._long_open_ordered is True:96return False9798# Check possible lot to buy?99if self.possible_lot == 0:100return False101102103104return self._is_all_true_in_group(ModelChecks.OPEN_LONG)105106def calc_possible_lot(self):107"""108Calc how many lot model can buy109:return:110"""111price_one_lot = self._last_price * self._count_in_lot112if price_one_lot != 0:113self._possible_lot = int(self._stock_limit // price_one_lot)114115if self._possible_lot == 0:116self._possible_lot = self._stock_lot_limit117else:118self._possible_lot = min(self._possible_lot, self.stock_lot_limit)119120@property121def stock_limit(self):122return self._stock_limit123124@stock_limit.setter125def stock_limit(self, limit):126self._stock_limit = limit127128@property129def count_in_lot(self):130return self._count_in_lot131132@count_in_lot.setter133def count_in_lot(self, count):134self._count_in_lot = count135136@property137def possible_lot(self):138return self._possible_lot139140@property141def stock_lot_limit(self) -> int:142return int(self._stock_lot_limit)143144@stock_lot_limit.setter145def stock_lot_limit(self, limit):146self._stock_lot_limit = limit147148@property149def is_ready_to_close_long(self) -> bool:150""" Check all specified checks, if all checks is true, it is time to close long order """151if self._long_available is not True:152return False153154# Is it already close?155if self.is_long_close_done is True:156return False157158# Is it already ordered?159if self._long_close_ordered is True:160return False161162# Is open already done?163if self._long_open_done is False:164return False165166# Is it triggered STOP,167if self.is_price_stop is True:168return True169170return self._is_all_true_in_group(ModelChecks.CLOSE_LONG)171172@property173def is_ready_to_open_short(self) -> bool:174""" Check all specified checks, if all checks is true, it is time to open short order """175if self._short_available is not True:176return False177return self._is_all_true_in_group(ModelChecks.OPEN_SHORT)178179@property180def is_ready_to_close_short(self) -> bool:181""" Check all specified checks, if all checks is true, it is time to close short order """182if self._short_available is not True:183return False184return self._is_all_true_in_group(ModelChecks.CLOSE_SHORT)185186@property187def is_long_open_done(self) -> bool:188return self._long_open_done189190@is_long_open_done.setter191def is_long_open_done(self, val: bool):192self._long_open_done = val193194@property195def is_long_close_done(self) -> bool:196return self._long_close_done197198@is_long_close_done.setter199def is_long_close_done(self, val: bool):200self._long_close_done = val201202@property203def is_long_open_ordered(self) -> bool:204return self._long_open_ordered205206@property207def is_long_close_ordered(self) -> bool:208return self._long_close_ordered209210def long_open_ordered(self):211self._long_open_ordered = True212213def long_close_ordered(self):214self._long_close_ordered = True215216@property217def last_price(self):218return self._last_price219220def set_last_price(self, last_price):221"""Set last price into model"""222self._prev_price = self._last_price223self._last_price = Decimal(last_price)224self.calc_possible_lot()225self._run_checks()226227@property228def is_long_available(self):229return self._long_available230231@property232def stock_drop_limit(self):233return self._stock_drop_limit234235@stock_drop_limit.setter236def stock_drop_limit(self, stock_drop_limit):237self._stock_drop_limit = stock_drop_limit238239@property240def is_price_stop(self) -> bool:241"""242Check price for STOP243:return:244"""245if self._stop_price is None:246# Stop price is no ready247return False248if self._last_price <= self._stop_price:249# Log data250LoggerFactory.get_business_logger_instance().add_event(BusinessLogger.STOP_LOOS,251self._ticker, self._last_price)252return True253254def set_average_position_price(self, avg_price):255self._avg_price = avg_price256self.calc_stop_price()257258def calc_stop_price(self):259if self._avg_price != 0:260max_loos = self._avg_price * self._stock_drop_limit / 100261self._stop_price = self._avg_price - max_loos262# Log data263LoggerFactory.get_business_logger_instance().add_event(BusinessLogger.CALC_STOP,264self._ticker, self._stop_price)265266267