Сбер: как некрасиво поступить на конкурсе красоты
Всё началось, когда я узнал про конкурс красоты кода от Сбера. Я как раз хотел поучаствовать в каком-нибудь эпичном конкурсе, а тут он мне и подвернулся, тем более что я - тот человек, которому есть что рассказать про красивый код. Я даже целую статью запилил о том, как писать красивый и понятный код. Так что я решил, что в данном случае мои шансы на победу - в отличие от остальных конкурсов - всё же больше нуля. Кроме того, я хотел выступить на конференции PiterPy (спойлер: хрен мне), чтобы рассказать там про красивый код и всё такое, поэтому участие в конкурсе и сравнение результатов было бы классным подспорьем.
Погромирование
🔗Про конкурс я узнал поздновато, оставалась где-то пара дней, и у меня была установка: не тратить на конкурс слишком много времени. Банально потому что тратить больше пары часов невыгодно - если меня не возьмут в победители, то по крайней мере двух часов мне не жалко. Поэтому я выделил 2 часа и ровно в 1:00 ночи накануне окончания конкурса я начал писать код.
Задание было про симулятор торговли на бирже, вот такое:
Напишите программу для симуляции торговли на финансовых рынках, включая методы для выполнения транзакций покупки и продажи активов и получения текущей стоимости портфеля.
from decimal import Decimal
from enum import Enum
class AssetPrice(Enum):
# Котировальный список активов.
LKOH = Decimal(5896)
SBER = Decimal(250)
Про торговлю на бирже я знаю только одно: картинку "стонкс". Поэтому первым делом я, конечно, добавил её в программу, чтобы казаться уверенным трейдером и человеком, который знает, о чём речь:
@dataclass
class PortfolioSimulator:
def __post_init__(self):
self.logo = (Path(__file__).parent / 'logo.txt').read_text()
def run(self):
""" Интерактивный режим """
self.print_greeting()
def print_greeting(self):
print(self.logo)
print('Добро пожаловать в симулятор торговли активами!')
print('Постарайтесь не разориться в первый день :>')
> python trading-simulation.py
⠀⠀⠀⠀⠀⢀⠤⠐⠒⠀⠀⠀⠒⠒⠤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⡠⠊⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⡔⠁⠀⠀⠀⠀⠀⢰⠁⠀⠀⠀⠀⠀⠀⠈⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⢰⠀⠀⠀⠀⠀⠀⠀⣾⠀⠀⠔⠒⠢⠀⠀⠀⢼⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⡆⠀⠀⠀⠀⠀⠀⠀⠸⣆⠀⠀⠙⠀⠀⠠⠐⠚⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠇⠀⠀⠀⠀⠀⠀⠀⠀⢻⠀⠀⠀⠀⠀⠀⡄⢠⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀
⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⣀⣀⡠⡌⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⢄⣲⣬⣶⣿⣿⡇⡇⠀
⠀⠀⠆⠀⠀⠀⠀⠀⠀⠀⠘⡆⠀⠀⢀⣀⡀⢠⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⢴⣾⣶⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀
⠀⠀⢸⠀⠀⠀⠀⠠⢄⠀⠀⢣⠀⠀⠑⠒⠂⡌⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⢿⣿⣿⣿⣿⣿⣿⣿⡇⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⠤⡀⠑⠀⠀⠀⡘⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⣡⣿⣿⣿⣿⣿⣿⣿⣇⠀
⠀⠀⢀⡄⠀⠀⠀⠀⠀⠀⠀⠈⢑⠖⠒⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⣴⣿⣿⣿⡟⠁⠈⠛⠿⣿⠀
⠀⣰⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢈⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠈⠀
⠈⣿⣿⣿⣿⣷⡤⣀⡀⠀⠀⢀⠎⣦⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣢⣿⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠘⣿⣿⣿⣿⣿⣄⠈⢒⣤⡎⠀⢸⣿⣿⣿⣷⣶⣤⣄⣀⠀⠀⠀⢠⣽⣿⠿⠿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠹⣿⣿⣿⣿⣿⣾⠛⠉⣿⣦⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⡗⣰⣿⣿⣿⠀⠀⣿⠀⠀⠀⠀⠀⠀⣀⡀⠀⠀
⠀⠀⡰⠋⠉⠉⠉⣿⠉⠀⠀⠉⢹⡿⠋⠉⠉⠉⠛⢿⣿⠉⠉⠋⠉⠉⠻⣿⠀⠀⣿⠞⠉⢉⣿⠚⠉⠉⠉⣿⠀
⠀⠀⢧⠀⠈⠛⠿⣟⢻⠀⠀⣿⣿⠁⠀⣾⣿⣧⠀⠘⣿⠀⠀⣾⣿⠀⠀⣿⠀⠀⠋⠀⢰⣿⣿⡀⠀⠛⠻⣟⠀
⠀⠀⡞⠿⠶⠄⠀⢸⢸⠀⠀⠿⢿⡄⠀⠻⠿⠇⠀⣸⣿⠀⠀⣿⣿⠀⠀⣿⠀⠀⣶⡀⠈⢻⣿⠿⠶⠆⠀⢸⡇
⠀⠀⠧⢤⣤⣤⠴⠋⠈⠦⣤⣤⠼⠙⠦⢤⣤⡤⠶⠋⠹⠤⠤⠿⠿⠤⠤⠿⠤⠤⠿⠳⠤⠤⠽⢤⣤⣤⠴⠟⠀
Добро пожаловать в симулятор торговли активами!
Постарайтесь не разориться в первый день :>
Заодно там видны "красивые" фишечки питона: датаклассы с их __post_init__
, чтение файла в одну строчку.
Далее я подумал, что прикольно было бы иметь несколько возможных алгоритмов ценообразования, чтобы можно было попробовать себя на каких-то симулируемых данных, а потом попробовать торговать и в реальных условиях. Поэтому я создал три стратегии:
1 - Стратегия "сегодня мне всё лень": цена акций просто всегда фиксированная. Just for fun.
class AssetPriceHistory(ABC):
"""
История цен активов.
Можно переопределять в дочерних классах, чтобы симулировать различные ситуации.
"""
@abstractmethod
def __iter__(self) -> Iterator[tuple[date, AssetPrice]]:
"""
Возвращает историю цен активов - кортежи вида (дата, цены активов).
"""
...
@dataclass
class ChillAssetPriceHistory(AssetPriceHistory):
"""
История цен активов, в которой цены не меняются.
Когда устали от трейдинга и просто хотите не думать.
"""
def __iter__(self) -> Iterator[tuple[date, AssetPrice]]:
today = date.today()
asset_price = AssetPrice()
for day in count():
date_ = today + timedelta(days=day)
yield date_, asset_price
Тут абстрактный базовый класс, type hints, итераторы и itertools.count()
. Красота!
2 - Стратегия "мне повезёт": цена скачет псевдорандомно от -50% до +50% базовой цены. Мастерство трейдинга тут не отточишь, зато можно понять уровень удачливости трейдера, что тоже немаловажно >:)
@dataclass
class ChaosAssetPriceHistory(AssetPriceHistory):
"""
История цен активов, в которой цены меняются случайным образом.
Только для самых отчаянных трейдеров.
"""
# множитель цены актива;
# по умолчанию актив может просесть на 50% или
# взлететь на 50% за один день, хе-хе
price_multiplier: tuple[float, float] = (0.5, 1.5)
seed: int = 42
def __post_init__(self):
self.random = Random()
self.random.seed(self.seed)
def __iter__(self) -> Iterator[tuple[date, AssetPrice]]:
today = date.today()
base_asset_price = AssetPrice()
for day in count():
date_ = today + timedelta(days=day)
if day == 0:
asset_price = base_asset_price
else:
asset_price = AssetPrice(**{
field: getattr(base_asset_price, field) * multiplier
for field in AssetPrice.__dataclass_fields__.keys()
if (multiplier := Decimal(self.random.uniform(*self.price_multiplier)))
})
yield date_, asset_price
Наверно, walrus в цикле и dict unpacking - это слишком мудрёно и некрасиво, зато можно в одном выражении задать цены на день. Ну если не понравится жюри - ну штош!
3 - Стратегия "как в реале": цена была взята просто из реальных данных акций Сбера и ещё чего-то за 10 дней - чтобы человек просто мог поторговать и понять, насколько всё плохо бывает.
@dataclass
class RealAssetPriceHistory(AssetPriceHistory):
"""
Настоящая история цен активов, взятая из исторических данных.
Без шуток.
В дальнейшем можно брать по API откуда-нибудь.
"""
def __iter__(self) -> Iterator[tuple[date, AssetPrice]]:
yield from (
(date(2023, 9, 10), AssetPrice(LKOH=Decimal(6669), SBER=Decimal(255))),
(date(2023, 9, 11), AssetPrice(LKOH=Decimal(6456), SBER=Decimal(256))),
(date(2023, 9, 12), AssetPrice(LKOH=Decimal(6729), SBER=Decimal(262))),
(date(2023, 9, 13), AssetPrice(LKOH=Decimal(6610), SBER=Decimal(258))),
(date(2023, 9, 14), AssetPrice(LKOH=Decimal(6519), SBER=Decimal(260))),
(date(2023, 9, 15), AssetPrice(LKOH=Decimal(6553), SBER=Decimal(260))),
(date(2023, 9, 16), AssetPrice(LKOH=Decimal(6527), SBER=Decimal(260))),
(date(2023, 9, 17), AssetPrice(LKOH=Decimal(6566), SBER=Decimal(263))),
)
Это, конечно, кустарщина, и в идеале нужно в этом классе получать реальные исторические данные по API из какого-нибудь сервиса, но это не для тестового задания. Поэтому просто забиваем значения ручками. Зато yield from
- красиво!
А вот как это встраивается в симулятор торговли:
@dataclass
class PortfolioSimulator:
history: AssetPriceHistory = field(default_factory=RealAssetPriceHistory) # dependency injection такое, можно подставлять разные истории и тренироваться на разных данных
def __post_init__(self):
self.days = iter(self.history)
self.next_day() # получаем первую дату и цены активов
...
def next_day(self):
""" Закончить день и получить цены нового дня """
self.current_date, self.current_prices = next(self.days)
Получился такой вот dependency injection (красиво!), чтобы можно было легко применять стратегии в нашем симуляторе. default_factory
по умолчанию ставит реальные исторические данные. В дальнейшем представители Сбера могут взять мой код, вставить туда свой исторический класс и сразу пушить во все репозитории, которые у них есть, и деплоить в продакшн. Очень удобно.
Далее осталось написать саму программу, которая бы обрабатывала пользовательский ввод, считала портфель и так далее. Я ничего особо крутого изобретать не стал, просто постарался логически разбить всё на маленькие кусочки, которые были простые для понимания, плюс добавил match-case
просто чтобы выпендриться и показать, что "Хоба! Я знаю про match-case
!" (его ведь для этого и создали, да?)
Ниже - код симулятора, всё неинтересное я превратил в троеточие или убрал, для любопытных есть репа.
@dataclass
class PortfolioSimulator:
history: AssetPriceHistory = field(default_factory=RealAssetPriceHistory) # dependency injection такое, можно подставлять разные истории и тренироваться на разных данных
cash: Decimal = Decimal(100_000) # начальный капитал
assets: defaultdict = field(default_factory=lambda: defaultdict(int)) # сколько активов у нас есть (в начале мы ничего не имеем)
@property
def asset_values(self) -> list[tuple[str, int, Decimal]]:
""" Стоимость активов """
return [
(asset, quantity, getattr(self.current_prices, asset) * quantity)
for asset in self.current_prices.__dataclass_fields__.keys()
if (quantity := self.assets[asset]) != 0 # не показываем то, чего не имеем
]
@property
def value(self) -> Decimal:
""" Стоимость портфеля """
return self.cash + sum(price for _, _, price in self.asset_values)
@property
def profit(self) -> Decimal:
""" Прибыль """
return self.value - self.initial_value
def run(self):
""" Интерактивный режим """
self.print_greeting()
while True:
self.print_summary()
try:
self.user_action()
except StopGameException:
break
self.print_result()
def print_greeting(self):
...
def print_summary(self):
...
def user_action(self) -> bool:
""" Выбор действия пользователя """
match input(dedent("""
Что вы хотите сделать?
1. Купить актив
2. Продать актив
3. Закончить день
4. Зафиксировать значения и завершить программу
""")):
case "1":
asset = input("Какой актив вы хотите купить? ")
amount = input_int("Сколько? ")
try:
self.buy(asset, amount)
except (WrongAssetName, NotEnoughCash) as exc:
print(exc)
else:
print(f"Вы купили {amount} {asset}")
sleep(1)
case "2":
asset = input("Какой актив вы хотите продать? ")
amount = input_int("Сколько? ")
try:
self.sell(asset, amount)
except (WrongAssetName, NotEnoughAsset) as exc:
print(exc)
else:
print(f"Вы продали {amount} {asset}")
sleep(1)
case "3":
try:
self.next_day()
except StopIteration as exc:
raise StopGameException() from exc
case "4":
raise StopGameException()
case _:
print("Неправильный выбор, попробуйте ещё раз.")
def print_result(self):
if (profit := self.profit) > 0:
print("Stonks! Вы закончили торговлю с прибылью! Отправляю данные о вас в налоговую! }:)")
elif profit == 0:
print("Ну вы хоть не разорились, это уже хорошо")
else:
print("Not stonks! Вы закончили торговлю в минус! Штош, бывает :[")
Мне кажется, что тут всё чисто и понятно, потому что код читается почти как естественный язык. За исключением def asset_values
, конечно - для конкурса можно было бы и развернуть в обычный for цикл, но я что-то не подумал.
Как раз уже было 3:00 ночи, я подумал, что больше ни минуты не потрачу на эту штуку. Я заполнил форму на сайте и отправил решение. Сайт просто сказал мне, что "окей чувак, всё получено", и больше ничего мне не пришло - ни email, никакого подтверждения вообще, как будто меня не существовало вовсе. Я даже до сих пор не уверен, есть я там в их системе или нет. До жути напоминает электронное голосование :]
Ожидание
🔗Ну и собственно я стал ждать. Было сказано, что победителей объявят через несколько дней. В заветный день я полез на сайт, чтобы поскорее узнать результаты - но даже и на следующее число на сайте ничего не обновилось. Я решил, что Сбер завалило красивым кодом, и они в спешке всё просматривают и не успевают. Но потом я читаю какой-то паблик в телеграме и внезапно вижу запись о том, что Сбер уже наградил победителей этого конкурса на своей SmartDev конференции. Так, ладно, сейчас посмотрим...
Я выпал в осадок, потому что на самом сайте никаких результатов не было, и почему вообще людей награждают на какой-то конференции, и почему мне никто не написал, что я дебил и что я плохо всё решил? В общем, это была какая-то мутная тема. Меня это, конечно, напрягло, и люди, которые читают Хабр, в комментариях к статье написали:
- Каком способом можно будет узнать результаты конкурса? Написано в правилах, что результаты будут сегодня, но не написано, каким способом их оглашают) Заранее спасибо)
- А где-то можно посмотреть решения победителей по направлению "Frontend"?
- Результаты опубликованы на день позже обозначенного срока, причем никакого уведомления мне как участнику не пришло, не обозначены критерии оценок, сколько баллов набрала моя работа, вывешен просто список фио "победителей". С кодом лидеров хоть бы дали возможность ознакомиться. Мутно как-то все.
- да, организация на 2 с плюсом. Никаких рассылок на почту. Откуда я должен знать, что оглашение результатов конкурса будет на какой-то конференции SmartDev? Этого нет в полных правилах конкурса.
Потом Сбер таки сделал жест и написал список победителей в формате {first_name} {last_name}, {city}
: Сделали по красоте: победители «Конкурса красоты кода»
Ну уж нет, Сберушка! Результаты должны быть честными, должны учить нас чему-то. Покажите мне победителя, расскажите, какой у него опыт, где он работает, как он научился писать по красоте (чтобы я так же смог), и главное, что я спрашиваю на любых разборках: покажите мне код!
Я, конечно, написал Оксимирону (псевдоним - Артём Фатхуллин), который награждал победителей, с вопросом "как мне связаться с победителями и посмотреть код", но он прочитал и ничего не ответил.
Реальность
🔗Раз уж никто мне ничего предоставлять не собирается, то я решил стать экспертом по сберовской красоте кода, то есть решил сам найти этих участников, кто они такие, что они написали, где можно посмотреть примеры кода и всё такое.
На самом деле я не мастер по OSINT, я даже сам себя в интернете найти не могу :D Но я постарался, честное слово, и я нашёл только двоих питонистов: мистера "Изящный код" aka Ивана Звонарёва из Ижевска, и мисс "Изящный код" aka Арину Жук из Москвы.
Арина любезно поделилась со мной своим решением по секции Data Science. Я не эксперт по ML, но мне оно понравилось - всё разложено по полочкам, легко читается, задачу решает. Вообще без претензий, по моему дилетантскому мнению - приз заслужен. Почему Сбер это не выложил - я хз.
Код Ивана я нашёл на гитхабе, позже в личной переписке он подтвердил, что он - это он, и это действительно тот код, что он отправил на конкурс и победил. Вот и сам код: https://github.com/Royal00Blood/Sber_task
Мне кажется, что он не самый красивый, и вот почему - по пунктам.
Это "интерфейс", но не в программистском понимании, а как бы "интерфейс взаимодействия с пользователем":
def interface():
exchange = FExchange()
action = None
print(" 1 - Sell \n",
"2 - Buy \n",
"3 - Show the value of the financial portfolio ",
"4 - exit")
while 1:
try:
action = int(input("Enter 1, 2, 3 or 4: "))
except ValueError:
print("Sorry! You enter no number!")
if action == 1:
exchange.sell_shares()
elif action == 2:
exchange.buy_shares()
elif action == 3:
exchange.e_cash_show()
elif action == 4:
exit()
Тут 3 момента:
- Ожидается, что весь интерфейс будет реализован в этом модуле (он же называется
Interface.py
!), однако на самом деле ввод-вывод размазан по модулям. Это некрасиво. action = None
нужно, потому что даже при плохом вводе содержимое цикла продолжает выполняться вместо того, чтобы сделать continue и попросить заново ввести корректное значение- При выборе 4 программа просто бескомпромиссно завершается. Это некрасиво,
exit()
лучше делать на "верхних" уровнях (где-нибудь вmain
), а из функций лучше просто выходить:elif action == 4: break
Ну ладно, что там в FExchange
?
from AssetPrice import AssetPrice
class FExchange:
"""
This is the main class that performs
the function of simulating the processes
of selling and buying shares on a financial exchange.
"""
def __init__(self):
self.__e_cash = 0 # The value of the financial portfolio
self.__fin_p = {a.name: 0 for a in AssetPrice} # Stocks in the financial portfolio
self.__f_abil = False # The possibility of selling something
def e_cash_show(self):
"""
:return:Displays the value of all shares in the portfolio
"""
self.__capital_calcul()
print(self.__e_cash)
def buy_shares(self):
"""
The function performs the process of buying shares from the available.
:return:
"""
for i in AssetPrice:
print(f"-----------> You have {i.name} shares of {self.__fin_p[i.name]} ")
print("You can to buy :")
for x in AssetPrice:
print(f"-----------> Company: {x.name}, coast: {x.value}")
self.__action_shares()
def sell_shares(self):
"""
The function performs the process of selling shares from a financial portfolio.
:return:
"""
for i in AssetPrice:
if not self.__f_abil:
if self.__fin_p[i.name] > 0:
self.__f_abil = True
print(f"You have {i.name} shares of {self.__fin_p[i.name]} ")
if not self.__f_abil:
print("You don't have any shares")
else:
self.__action_shares(incr=False)
def __action_shares(self, incr=True):
"""
Function for changing the values of stocks in the financial portfolio.
:param incr: А logical variable that determines the increase or decrease of a block of shares.
:return:
"""
while 1:
n_promotion = input('Enter name of the promotion: ')
if n_promotion in self.__fin_p:
break
else:
print("Enter again. You have mistake. (Example: SBER)")
while 1:
try:
c_promotion = int(input('Enter the number of shares to buy: '))
except ValueError:
print("Enter again")
else:
break
if incr:
self.__fin_p[n_promotion] += c_promotion
else:
self.__fin_p[n_promotion] -= c_promotion
def __capital_calcul(self):
"""
The function calculates the sum of all the shares in the financial portfolio.
:return: Current value of the financial portfolio.
"""
for i in AssetPrice:
self.__e_cash += self.__fin_p[i.name] * i.value
- Почему
__f_abil
,__fin_p
,__e_cash
называются так, как называются? Как же читаемость?__e_cash
- это цифровой рубль? for i in AssetPrice
: - почемуi
, а неasset
?- Кажется, понятие "деньги на руках" в этом коде отсутствует в принципе, поэтому в
__action_shares
нет никакой проверки на лимиты. Кому нужно 100000000000000000 акций сбера? Хоба!
Enter 1, 2, 3 or 4: 2
-----------> You have LKOH shares of 0
-----------> You have SBER shares of 4
You can to buy :
-----------> Company: LKOH, coast: 5896
-----------> Company: SBER, coast: 250 <--- хочу вот это побережье
Enter name of the promotion: SBER
Enter the number of shares to buy: 100000000000000000
Enter 1, 2, 3 or 4: 3
25000000000000004500 <---- мама, я богат!
- В
__capital_calcul
есть side effect, а они очень опасны! Будьте осторожны, а то вдруг при выводе портфолио на экран оно будет само увеличиваться каждый раз? Стоп, что?..
Enter 1, 2, 3 or 4: 3 <-- покажи стоимость портфолио
1500
Enter 1, 2, 3 or 4: 3
2500
Enter 1, 2, 3 or 4: 3
3500
__action_shares
принимает параметрincr=True/False
, типа "купить или продать", но код один и тот же, поэтому при продаже спрашивается, что вы хотите купить:
Enter 1, 2, 3 or 4: 1 <--- продать!
You have SBER shares of 100000000000000004
Enter name of the promotion: LKOH
Enter the number of shares to buy: 9999 <--- что хотите купить?
- Да и вообще продавать можно не то, что покупал, какая нафиг разница! Все эти акции-шмакции только всё усложняют.
Я уже приноровился к местным правилам, поэтому вот моя рабочая стратегия, которая приведёт к успеху.
Сначала у нас ничего нет, ничего продать не можем:
> python main.py
1 - Sell
2 - Buy
3 - Show the value of the financial portfolio 4 - exit
Enter 1, 2, 3 or 4: 3
0
Enter 1, 2, 3 or 4: 3
0
Enter 1, 2, 3 or 4: 1
You don't have any shares
Покупаем сбер на всю котлету:
Enter 1, 2, 3 or 4: 2
-----------> You have LKOH shares of 0
-----------> You have SBER shares of 0
You can to buy :
-----------> Company: LKOH, coast: 5896
-----------> Company: SBER, coast: 250
Enter name of the promotion: SBER
Enter the number of shares to buy: 100
Потом проверяем баланс пару раз, чтобы стало побольше:
Enter 1, 2, 3 or 4: 3
25000
Enter 1, 2, 3 or 4: 3
50000
У меня, конечно, есть только 100 акций Сбера, но Лукойл мне так не нравится, что продам его, чтоб было прям отрицательное число акций:
Enter 1, 2, 3 or 4: 1
You have SBER shares of 100
Enter name of the promotion: LKOH
Enter the number of shares to buy: 100
Enter 1, 2, 3 or 4: 3
-514600
Блин, теперь баланс отрицательный! Попробую "отыграться" проверенной схемой - множественной проверкой баланса:
Enter 1, 2, 3 or 4: 3
-514600
Enter 1, 2, 3 or 4: 3
-1079200
Enter 1, 2, 3 or 4: 3
-1643800
Enter 1, 2, 3 or 4: 3
-2208400
Чёрт, теперь баланс уменьшается! У меня 100 Сбера, но попробую продать миллион:
Enter 1, 2, 3 or 4: 1
Enter name of the promotion: SBER
Enter the number of shares to buy: 1000000 <--- это на самом деле продажа
Enter 1, 2, 3 or 4: 3
-252773000
Ладно, кажется, машина меня переиграла. Я должен 252 миллиона. Не буду усугублять.
И заметьте, насколько я плохой трейдер: все эти миллионы я просадил за один день! Хорошо, что в этом симуляторе только один день и есть (то есть цены вообще не меняются) - иначе всё было бы ещё хуже...
И чо
🔗Все, кто участвовал в коде по питону - теперь вы знаете, как надо было писать, чтобы победить.
Рецензия от погромиста:
- Это не плохой код, но и не красивый
- Этот код не решает задачу (где симуляция изменения цен?)
- Этот код работает с критическими ошибками
Пожалуйста, заметьте, что я тут совершенно не в претензии к Ивану. Мы с ним поговорили немного в телеграме, он самоучка, грызёт Питон, и у меня к таким людям исключительно чувство уважения.
Но у меня есть претензия к Сберу. Вы везде рекламируете свой конкурс, мы шлём вам свой код, вы втихую награждаете каких-то людей, и больше ни слова про этот конкурс. Никаких результатов, кроме имени, фамилии и города. Я должен сам искать этих участников, чтобы узнать результат.
Давай, Сбер, скажи, например, что это я ошибся, и это другой Иван Звонарёв из другого Ижевска выложил решение с конкурса и не отрицал, что он победитель. Или что ты ошибся только с одним участником, а у других участников всё как надо. А код решений вы не успели выложить. А Артём Фатхуллин всегда только читает, но ничего не отвечает, такой он человек. Скажи всё, что ты должен сказать в таких случаях - мы все всё понимаем.
Да, я не открыл Америку. Просто в очередной раз убедился.