From 23ad43bcb5157e5cc91d2cac1d896be185f0018e Mon Sep 17 00:00:00 2001 From: vestor-dev <182824106+vestor-dev@users.noreply.github.com> Date: Mon, 25 Nov 2024 07:37:21 +0000 Subject: [PATCH 1/5] feat: Add new fields and crud methods for Position --- .../1a6fada80369_add_postion_columns.py | 34 ++++++++++ web_app/db/crud.py | 65 +++++++++++++++++++ web_app/db/models.py | 5 ++ 3 files changed, 104 insertions(+) create mode 100644 web_app/alembic/versions/1a6fada80369_add_postion_columns.py diff --git a/web_app/alembic/versions/1a6fada80369_add_postion_columns.py b/web_app/alembic/versions/1a6fada80369_add_postion_columns.py new file mode 100644 index 00000000..36162a5c --- /dev/null +++ b/web_app/alembic/versions/1a6fada80369_add_postion_columns.py @@ -0,0 +1,34 @@ +"""add postion columns + +Revision ID: 1a6fada80369 +Revises: 0537a9a5e841 +Create Date: 2024-11-25 07:34:11.693095 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '1a6fada80369' +down_revision = '0537a9a5e841' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('position', sa.Column('is_protection', sa.Boolean(), nullable=True)) + op.add_column('position', sa.Column('liquidation_bonus', sa.Float(), nullable=True)) + op.add_column('position', sa.Column('is_liquidated', sa.Boolean(), nullable=True)) + op.add_column('position', sa.Column('datetime_liquidation', sa.DateTime(), nullable=False)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('position', 'datetime_liquidation') + op.drop_column('position', 'is_liquidated') + op.drop_column('position', 'liquidation_bonus') + op.drop_column('position', 'is_protection') + # ### end Alembic commands ### diff --git a/web_app/db/crud.py b/web_app/db/crud.py index f8af9b70..86910ef1 100644 --- a/web_app/db/crud.py +++ b/web_app/db/crud.py @@ -472,6 +472,71 @@ def save_current_price(self, position: Position, price_dict: dict) -> None: self.write_to_db(position) except SQLAlchemyError as e: logger.error(f"Error while saving current_price for position: {e}") + + def liquidate_position(self, position_id: int) -> bool: + """ + Marks a position as liquidated by setting `is_liquidated` to True + and updating `datetime_liquidation` to the current timestamp. + + :param position_id: ID of the position to be liquidated. + :return: True if the update was successful, False otherwise. + """ + with self.Session() as db: + try: + # Fetch the position by ID + position = db.query(Position).filter(Position.id == position_id).first() + + if not position: + logger.warning(f"Position with ID {position_id} not found.") + return False + + position.is_liquidated = True + position.datetime_liquidation = datetime.now() + + self.write_to_db(position) + logger.info(f"Position {position_id} successfully liquidated.") + return True + + except SQLAlchemyError as e: + logger.error(f"Error liquidating position {position_id}: {str(e)}") + db.rollback() + return False + def get_all_liquidated_positions(self) -> list[dict]: + """ + Retrieves all positions where `is_liquidated` is True. + + :return: A list of dictionaries containing the liquidated positions. + """ + with self.Session() as db: + try: + liquidated_positions = ( + db.query(Position) + .filter(Position.is_liquidated == True) + .all() + ) + + # Convert ORM objects to dictionaries for return + return [ + { + "id": position.id, + "user_id": position.user_id, + "token_symbol": position.token_symbol, + "amount": position.amount, + "multiplier": position.multiplier, + "created_at": position.created_at, + "status": position.status.value, + "start_price": position.start_price, + "is_protection": position.is_protection, + "liquidation_bonus": position.liquidation_bonus, + "is_liquidated": position.is_liquidated, + "datetime_liquidation": position.datetime_liquidation + } + for position in liquidated_positions + ] + + except SQLAlchemyError as e: + logger.error(f"Error retrieving liquidated positions: {str(e)}") + return [] class AirDropDBConnector(DBConnector): diff --git a/web_app/db/models.py b/web_app/db/models.py index 7115b662..841ee5cc 100644 --- a/web_app/db/models.py +++ b/web_app/db/models.py @@ -17,6 +17,7 @@ ForeignKey, Integer, String, + Float ) from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.sql import func @@ -77,6 +78,10 @@ class Position(Base): default="pending", ) start_price = Column(DECIMAL, nullable=False) + is_protection = Column(Boolean, default=False) + liquidation_bonus = Column(Float, default=0.0) + is_liquidated = Column(Boolean, default=False) + datetime_liquidation = Column(DateTime, nullable=False) class AirDrop(Base): From e4dbff274f8586e4505a67deb2b5b3795581acf1 Mon Sep 17 00:00:00 2001 From: vestor-dev <182824106+vestor-dev@users.noreply.github.com> Date: Mon, 25 Nov 2024 07:46:15 +0000 Subject: [PATCH 2/5] add doc-string --- .../1a6fada80369_add_postion_columns.py | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/web_app/alembic/versions/1a6fada80369_add_postion_columns.py b/web_app/alembic/versions/1a6fada80369_add_postion_columns.py index 36162a5c..efd7e709 100644 --- a/web_app/alembic/versions/1a6fada80369_add_postion_columns.py +++ b/web_app/alembic/versions/1a6fada80369_add_postion_columns.py @@ -1,15 +1,23 @@ -"""add postion columns +""" +Add new columns to the `position` table. Revision ID: 1a6fada80369 Revises: 0537a9a5e841 Create Date: 2024-11-25 07:34:11.693095 +This migration introduces the following changes to the `position` table: +- Adds `is_protection` (Boolean): Indicates whether the position has protection enabled. +- Adds `liquidation_bonus` (Float): Represents any bonus applied during the liquidation process. +- Adds `is_liquidated` (Boolean): Marks whether the position has been liquidated. +- Adds `datetime_liquidation` (DateTime): Stores the timestamp of when the position was liquidated. +These changes enhance the functionality of the `position` table by allowing better tracking of liquidation-related events and attributes. """ + from alembic import op import sqlalchemy as sa -# revision identifiers, used by Alembic. +# Revision identifiers, used by Alembic. revision = '1a6fada80369' down_revision = '0537a9a5e841' branch_labels = None @@ -17,18 +25,32 @@ def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### + """ + Apply the upgrade. + + This function adds four new columns to the `position` table: + - `is_protection`: A boolean field that indicates whether protection is enabled for the position. + - `liquidation_bonus`: A float field to store any bonuses applied during liquidation. + - `is_liquidated`: A boolean field to indicate if the position has been liquidated. + - `datetime_liquidation`: A datetime field to record when the liquidation occurred. + """ op.add_column('position', sa.Column('is_protection', sa.Boolean(), nullable=True)) op.add_column('position', sa.Column('liquidation_bonus', sa.Float(), nullable=True)) op.add_column('position', sa.Column('is_liquidated', sa.Boolean(), nullable=True)) op.add_column('position', sa.Column('datetime_liquidation', sa.DateTime(), nullable=False)) - # ### end Alembic commands ### def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### + """ + Revert the upgrade. + + This function removes the four columns added to the `position` table: + - `is_protection` + - `liquidation_bonus` + - `is_liquidated` + - `datetime_liquidation` + """ op.drop_column('position', 'datetime_liquidation') op.drop_column('position', 'is_liquidated') op.drop_column('position', 'liquidation_bonus') op.drop_column('position', 'is_protection') - # ### end Alembic commands ### From 71a21a816bf6856847bfb0d9d9a9cdce36a7c819 Mon Sep 17 00:00:00 2001 From: vestor-dev <182824106+vestor-dev@users.noreply.github.com> Date: Mon, 25 Nov 2024 07:47:41 +0000 Subject: [PATCH 3/5] fmt --- .../1a6fada80369_add_postion_columns.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/web_app/alembic/versions/1a6fada80369_add_postion_columns.py b/web_app/alembic/versions/1a6fada80369_add_postion_columns.py index efd7e709..3f039b36 100644 --- a/web_app/alembic/versions/1a6fada80369_add_postion_columns.py +++ b/web_app/alembic/versions/1a6fada80369_add_postion_columns.py @@ -18,8 +18,8 @@ # Revision identifiers, used by Alembic. -revision = '1a6fada80369' -down_revision = '0537a9a5e841' +revision = "1a6fada80369" +down_revision = "0537a9a5e841" branch_labels = None depends_on = None @@ -34,10 +34,12 @@ def upgrade() -> None: - `is_liquidated`: A boolean field to indicate if the position has been liquidated. - `datetime_liquidation`: A datetime field to record when the liquidation occurred. """ - op.add_column('position', sa.Column('is_protection', sa.Boolean(), nullable=True)) - op.add_column('position', sa.Column('liquidation_bonus', sa.Float(), nullable=True)) - op.add_column('position', sa.Column('is_liquidated', sa.Boolean(), nullable=True)) - op.add_column('position', sa.Column('datetime_liquidation', sa.DateTime(), nullable=False)) + op.add_column("position", sa.Column("is_protection", sa.Boolean(), nullable=True)) + op.add_column("position", sa.Column("liquidation_bonus", sa.Float(), nullable=True)) + op.add_column("position", sa.Column("is_liquidated", sa.Boolean(), nullable=True)) + op.add_column( + "position", sa.Column("datetime_liquidation", sa.DateTime(), nullable=False) + ) def downgrade() -> None: @@ -50,7 +52,7 @@ def downgrade() -> None: - `is_liquidated` - `datetime_liquidation` """ - op.drop_column('position', 'datetime_liquidation') - op.drop_column('position', 'is_liquidated') - op.drop_column('position', 'liquidation_bonus') - op.drop_column('position', 'is_protection') + op.drop_column("position", "datetime_liquidation") + op.drop_column("position", "is_liquidated") + op.drop_column("position", "liquidation_bonus") + op.drop_column("position", "is_protection") From 93c272d96f0ed7a73463060ee2be209e0d853214 Mon Sep 17 00:00:00 2001 From: vestor-dev <182824106+vestor-dev@users.noreply.github.com> Date: Mon, 25 Nov 2024 07:52:01 +0000 Subject: [PATCH 4/5] fmt --- web_app/alembic/versions/1a6fada80369_add_postion_columns.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web_app/alembic/versions/1a6fada80369_add_postion_columns.py b/web_app/alembic/versions/1a6fada80369_add_postion_columns.py index 3f039b36..fdafe39f 100644 --- a/web_app/alembic/versions/1a6fada80369_add_postion_columns.py +++ b/web_app/alembic/versions/1a6fada80369_add_postion_columns.py @@ -10,7 +10,8 @@ - Adds `liquidation_bonus` (Float): Represents any bonus applied during the liquidation process. - Adds `is_liquidated` (Boolean): Marks whether the position has been liquidated. - Adds `datetime_liquidation` (DateTime): Stores the timestamp of when the position was liquidated. -These changes enhance the functionality of the `position` table by allowing better tracking of liquidation-related events and attributes. +These changes enhance the functionality of the `position` table by +allowing better tracking of liquidation-related events and attributes. """ from alembic import op @@ -29,7 +30,7 @@ def upgrade() -> None: Apply the upgrade. This function adds four new columns to the `position` table: - - `is_protection`: A boolean field that indicates whether protection is enabled for the position. + - `is_protection`: A boolean field that indicates whether protection is enabled. - `liquidation_bonus`: A float field to store any bonuses applied during liquidation. - `is_liquidated`: A boolean field to indicate if the position has been liquidated. - `datetime_liquidation`: A datetime field to record when the liquidation occurred. From 2f21dc32d987b0948f1f807c70b312f455278593 Mon Sep 17 00:00:00 2001 From: vestor-dev <182824106+vestor-dev@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:02:16 +0000 Subject: [PATCH 5/5] feat: apply change requests --- web_app/db/crud.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/web_app/db/crud.py b/web_app/db/crud.py index 86910ef1..1187bbb3 100644 --- a/web_app/db/crud.py +++ b/web_app/db/crud.py @@ -501,6 +501,7 @@ def liquidate_position(self, position_id: int) -> bool: logger.error(f"Error liquidating position {position_id}: {str(e)}") db.rollback() return False + def get_all_liquidated_positions(self) -> list[dict]: """ Retrieves all positions where `is_liquidated` is True. @@ -513,12 +514,11 @@ def get_all_liquidated_positions(self) -> list[dict]: db.query(Position) .filter(Position.is_liquidated == True) .all() - ) + ).scalar() # Convert ORM objects to dictionaries for return return [ { - "id": position.id, "user_id": position.user_id, "token_symbol": position.token_symbol, "amount": position.amount, @@ -526,8 +526,6 @@ def get_all_liquidated_positions(self) -> list[dict]: "created_at": position.created_at, "status": position.status.value, "start_price": position.start_price, - "is_protection": position.is_protection, - "liquidation_bonus": position.liquidation_bonus, "is_liquidated": position.is_liquidated, "datetime_liquidation": position.datetime_liquidation }