Giter VIP home page Giter VIP logo

frequenz-api-electricity-trading's People

Contributors

camille-bouvy-frequenz avatar daniel-zullo-frequenz avatar david-natingga-frequenz avatar dependabot[bot] avatar idlir-shkurti-frequenz avatar matthias-wende-frequenz avatar

Watchers

 avatar  avatar

frequenz-api-electricity-trading's Issues

Remove unnecessary optional keywords and add documentation to `UpdateGridpoolOrderRequest`

What's needed?

There are redundant optional keywords being used in the UpdateGridpoolOrderRequest message.

Proposed solution

// Request to update an existing order for a given Gridpool.
message UpdateGridpoolOrderRequest {
  // Represents the order properties that can be updated after an order has been
  // placed. At least one of the optional fields must be set for an update to
  // take place.
  message UpdateOrder {
-   // The updated limit price at which the contract is to be traded.
+   // Optional; The updated limit price at which the contract is to be traded.
    // This is the maximum price for a BUY order or the minimum price for a SELL
    // order.
-    optional frequenz.api.common.v1.market.Price price = 2;
+   frequenz.api.common.v1.market.Price price = 2;

-   // The updated quantity of the contract being traded, specified in MWh.
+  // Optional; The updated quantity of the contract being traded, specified in MWh.
-   optional frequenz.api.common.v1.market.Energy quantity = 3;
+  frequenz.api.common.v1.market.Energy quantity = 3;

-   // Applicable for STOP_LIMIT orders. This is the updated stop price that
+   // Optional; Applicable for STOP_LIMIT orders. This is the updated stop price that
    // triggers the limit order.
-   optional frequenz.api.common.v1.market.Price stop_price = 4;
+  frequenz.api.common.v1.market.Price stop_price = 4;

-   // Applicable for ICEBERG orders. This is the updated price difference
+   // Optional; Applicable for ICEBERG orders. This is the updated price difference
    // between the peak price and the limit price.
-   optional frequenz.api.common.v1.market.Price peak_price_delta = 5;
+  frequenz.api.common.v1.market.Price peak_price_delta = 5;

-   // Applicable for ICEBERG orders. This is the updated quantity of the order
+   // Optional; Applicable for ICEBERG orders. This is the updated quantity of the order
    // to be displayed in the order book.
-   optional frequenz.api.common.v1.market.Energy display_quantity = 6;
+  frequenz.api.common.v1.market.Energy display_quantity = 6;

-   // Updated execution options such as All or None, Fill or Kill, etc.
+   // Optional; Updated execution options such as All or None, Fill or Kill, etc.
    optional OrderExecutionOption execution_option = 7;

-   // This is an updated timestamp defining the time after which the order
+   // Optional; This is an updated timestamp defining the time after which the order
    // should be cancelled if not filled. The timestamp is in UTC.
    google.protobuf.Timestamp valid_until = 8;

-    // Updated user-defined payload individual to a specific order.
+   // Optional; Updated user-defined payload individual to a specific order.
    // This can be any data that the user wants to associate with the order.
    google.protobuf.Struct payload = 9;

-   // Updated user-defined tag to group related orders.
+   // Optional; Updated user-defined tag to group related orders.
    optional string tag = 10;
  }

  // ID of the Gridpool the order belongs to.
  uint64 gridpool_id = 1;

  // The order identifier
  uint64 order_id = 2;

  // Field mask specifying which fields should be updated
  google.protobuf.FieldMask update_mask = 3;

  // The fields that can be updated
  UpdateOrder update_order_fields = 4;
}

// ... 

// Represents an order in the electricity market.
message Order {
  // The delivery area where the contract is to be delivered. The representation
  // of the delivery area may vary by jurisdiction.
  frequenz.api.common.v1.grid.DeliveryArea delivery_area = 2;

  // The delivery period for the contract, specified as a start and end
  // timestamp in UTC. It represents the period during which the contract is
  // expected to be fulfilled.
  frequenz.api.common.v1.grid.DeliveryPeriod delivery_period = 3;

  // The type of order, such as LIMIT, STOP_LIMIT, ICEBERG etc.
  // This determines how the order is to be executed in the market.
  OrderType type = 4;

  // Indicates if the order is on the Buy or Sell side of the market.
  MarketSide side = 5;

  // The limit price at which the contract is to be traded. This is the maximum
  // price for a BUY order or the minimum price for a SELL order.
  frequenz.api.common.v1.market.Price price = 6;

  // The quantity of the contract being traded, specified in MWh.
  frequenz.api.common.v1.market.Energy quantity = 7;

- // Applicable for STOP_LIMIT orders. This is the stop price that triggers the
+ // Optional; Applicable for STOP_LIMIT orders. This is the stop price that triggers the
  // limit order.
-  optional frequenz.api.common.v1.market.Price stop_price = 8;
+ frequenz.api.common.v1.market.Price stop_price = 8;

- // Applicable for ICEBERG orders. This is the price difference between the
+ // Optional; Applicable for ICEBERG orders. This is the price difference between the
  // peak price and the limit price.
- optional frequenz.api.common.v1.market.Price peak_price_delta = 9;
+ frequenz.api.common.v1.market.Price peak_price_delta = 9;

-  // Applicable for ICEBERG orders. This is the quantity of the order to be
+  // Optional; Applicable for ICEBERG orders. This is the quantity of the order to be
  // displayed in the order book.
- optional frequenz.api.common.v1.market.Energy display_quantity = 10;
+ frequenz.api.common.v1.market.Energy display_quantity = 10;

  // Optional; Execution options such as All or None, Fill or Kill, etc.
  optional OrderExecutionOption execution_option = 11;

- // Do not use if ExecutionOption is set to FOK or IOC. This is an optional UTC
+ // Optional; Do not use if ExecutionOption is set to FOK or IOC. This is an optional UTC
  // timestamp defining the time after which the order should be cancelled if
  // not filled.
- optional google.protobuf.Timestamp valid_until = 12;
+ google.protobuf.Timestamp valid_until = 12;

  // Optional user-defined payload individual to a specific order. This can be
  // any data that needs to be associated with the order.
  //
  // The field can store e.g. JSON objects containing details involved in the
  // order. This feature can simplify application development by eliminating the
  // need for complicated state management to remember the specifics of each
  // order.
  //
  // By embedding this "state" within the order itself, you can include
  // specifics like which microgrids consume or provide how much power. This
  // makes it easier to manage complex orders and can simplify the logic
  // required in applications.
  //
  // Example JSON payload:
  // {
  //   "microgrids": [
  //     {
  //       "microgrid_id": "1",
  //       "mwh": 1.0
  //     },
  //     {
  //       "microgrid_id": "2",
  //       "mwh": 0.5
  //     }
  //   ]
  // }
  //
  // In this example, if the order is exectuted, these microgrids might consume
  // the electricity mentioned in the example JSON payload.
- optional google.protobuf.Struct payload = 13;
+ google.protobuf.Struct payload = 13;

  // Optional user-defined tag to group related orders.
  optional string tag = 14;
}

Use cases

No response

Alternatives and workarounds

No response

Additional context

No response

Remove state filter from OrderFilter

What's needed?

The state filter should be removed from the OrderFilter.

// Optional filter for order state.
repeated OrderState states = 1;

Proposed solution

// Parameters for filtering Gridpool orders.
//
// !!! note
//     Multiple filters can be used in combination to narrow down the returned
//     results. For example, you can apply both state and side filters
//     simultaneously to list only the open orders on the buy side of the
//     market.
message GridpoolOrderFilter {
-  // Optional filter for order state.
-  repeated OrderState states = 1;

  // Optional filter for order side.
-  optional MarketSide side = 2;
+  optional MarketSide side = 1;

  // Optional filter for delivery period.
-  frequenz.api.common.v1.grid.DeliveryPeriod delivery_period = 3;
+  frequenz.api.common.v1.grid.DeliveryPeriod delivery_period = 2;

  // Optional filter for delivery area.
-  frequenz.api.common.v1.grid.DeliveryArea delivery_area = 4;
+  frequenz.api.common.v1.grid.DeliveryArea delivery_area = 3;

  // Optional filters the listed orders by their associated tag.
-  optional string tag = 5;
+  optional string tag = 4;
}

Use cases

No response

Alternatives and workarounds

No response

Additional context

No response

Return gridpool trades

What's needed?

Currently there is no way to retrieve individual gridpool level trades data. The difference between trades and orders is that an order can result into multiple trades each having its own status, price and quantity. Also an order has its own initial quantity.

Proposed solution

Introduce two new RPC endpoints:

// Service providing operations related to order management.
service ElectricityTradingService {

  // ....
  
  // Lists all trades for a given Gridpool.
  rpc ListGridpoolTrades(ListGridpoolTradesRequest)
      returns (ListGridpoolTradesResponse);

  // Stream trades for a given Gridpool.
  rpc ReceiveGridpoolTradesStream(ReceiveGridpoolTradesStreamRequest)
      returns (stream ReceiveGridpoolTradesStreamResponse);

  // ....

}

Note on TradeState: see this related issue here

// Enum for the state of a trade.
enum TradeState {
   // ...
}
// Represents a private trade in the electricity market.
// 
// !!! note
//     This represents either the buy or sell side of a trade which is different to 
//     public trade information which always represents both sides of a market.
message Trade {
  // ID of the trade.
  uint64 id = 1;

  // ID of the order.
  uint64 order_id = 2;

  // Indicates if the trades order was on the Buy or Sell side of the market.
  MarketSide side = 3;

  // Delivery area of the trade.
  frequenz.api.common.v1.grid.DeliveryArea delivery_area = 4;

  // The delivery period for the contract.
  frequenz.api.common.v1.grid.DeliveryPeriod delivery_period = 5;

  // UTC Timestamp of the trades execution time.
  google.protobuf.Timestamp execution_time = 6;

  // The price at which the trade was executed.
  frequenz.api.common.v1.market.Price price = 7;

  // The executed quantity of the trade.
  frequenz.api.common.v1.market.Energy quantity = 8;

  // Current state of the trade.
  TradeState state = 9;
}
// Parameters for filtering Gridpool trades.
//
// !!! note
//     Multiple filters can be used in combination to narrow down the returned
//     results. For example, you can apply both state and side filters
//     simultaneously to list only the trades on the buy side of the
//     market.
message GridpoolTradeFilter {
  // Optional filter for the trade state.
  repeated TradeState states = 1;

  // Optional filter for the given order id´s.
  repeated uint64 order_id_list = 2;

  // Optional filter for the trades order side.
  optional MarketSide side = 3;

  // Optional filter for delivery period.
  frequenz.api.common.v1.grid.DeliveryPeriod delivery_period = 4;

  // Optional filter for delivery area.
  frequenz.api.common.v1.grid.DeliveryArea delivery_area = 5;
}
// Request to retrieve a list of trades for a specific Gridpool.
message ListGridpoolTradesRequest {
  // The Gridpool to retrieve the trades for.
  uint64 gridpool_id = 1;

  // Optional Gridpool trades filter.
  GridpoolTradeFilter filter = 2;

  // Pagination parameters.
  frequenz.api.common.v1.pagination.PaginationParams pagination_params = 3;
}

// Response from listing trades for a given Gridpool.
message ListGridpoolTradesResponse {
  // List of all listed trades with their details.
  repeated Trade trades_list = 1;

  // Metadata for pagination, including token for next page to retrieve.
  frequenz.api.common.v1.pagination.PaginationInfo pagination_info = 2;
}

// Subscribe to the stream of gridpool trades.
// This method provides real-time updates on newly executed gridpool trades,
// making it useful dynamic analytics and real-time decision-making.
message ReceiveGridpoolTradesStreamRequest {
  // Optional filter to specify which trades should be included in the stream.
  TradeFilter filter = 1;
}

// Response to a subscription request for a stream of Gridpool trades.
// Real-time information on trades is pushed through this response.
message ReceiveGridpoolTradesStreamResponse {
  // The trade that has been executed and is being broadcasted in
  // real-time.
  Trade trade = 1;
}

Use cases

No response

Alternatives and workarounds

No response

Additional context

No response

Remove `filled_quantity` field from `OrderDetail` message

What's needed?

The filled_quantity field has redundant information that can be deduced by a simple subtraction of open_quantity from order.quantity.

Proposed solution

We can add this a back as a property to the SDK at a higher level above the API client or it can simply be calculated in any application.

Use cases

No response

Alternatives and workarounds

No response

Additional context

No response

Add unit conversion methods to Energy type

What's needed?

Currently the Energy type only supports MWh. However, the energy forecasts are given in Wh. A function to convert between units is missing.

Proposed solution

Adding functions to convert the different unit types in the _types.py class (see for example what was done in the SDK Energy type here).

Use cases

Integration of the Client API into the trading app.

Alternatives and workarounds

Currently we can do the conversion manually on the app side but it is pretty hacky. This should only be a temporary solution.

Additional context

No response

Rename `public_trade_lists` to `public_trades_list` for better clarity

What's needed?

Some properties should be renamed for better clarity.

Proposed solution

// ...

// ListPublicTradesResponse is a message that contains a list of historic public
// trades.
// This dataset is vital for tasks such as training machine learning models,
// backtesting trading strategies, and conducting market analysis.
message ListPublicTradesResponse {
  // List of all public trades that met the specified filtering criteria.
- repeated PublicTrade public_trade_lists = 1;
+ repeated PublicTrade public_trades_list = 1;

  // Metadata for pagination, including token for next page to retrieve.
  frequenz.api.common.v1.pagination.PaginationInfo pagination_info = 2;
}

// ...

Use cases

No response

Alternatives and workarounds

No response

Additional context

No response

Revert copying proto definitions from the frequenz-api-common repository.

What's needed?

Unfortunately the frequenz python sdk depends on an older version of the frequenz-common repository. The python tooling is not able to cope with libraries depending of different versions of libraries and therefore, to work around this problem, we removed the dependency to the frequenz-api-common repository in #24.

This issue is a reminder to revert this change, once the sdk is updated to the same version that this api depends on.

Proposed solution

No response

Use cases

No response

Alternatives and workarounds

No response

Additional context

No response

Return full order revision history

What's needed?

Currently only the last state of an order is returned but not the full revision history. This might be interesting for some uses cases to train models or to impact decision making.

Proposed solution

No response

Use cases

No response

Alternatives and workarounds

No response

Additional context

No response

Split `OrderState` into `OrderState` and `TradeState`

What's needed?

Currently OrderState is used to also return the state of a trade. This might be confusing to understand. There are two solutions to the problem. One is to seperate the state of orders and trades or to rename OrderState to just State.

Proposed solution

Remove the trade statuses from OrderState and create a new TradeState message.

// Enum for the state of an order.
enum TradeState {
  // UNSPECIFIED: The state is not known.
  TRADE_STATE_UNSPECIFIED = 0;

  // ACTIVE: The trade has been executed in the market.
  TRADE_STATE_ACTIVE = 1;

  // CANCEL_REQUESTED: A cancellation request for the trade has been submitted.
  ORDER_STATE_CANCEL_REQUESTED = 2;

  // CANCEL_REJECTED: The trade cancellation request was rejected.
  ORDER_STATE_CANCEL_REJECTED = 3;

  // CANCELED: The trade has been cancelled. This can occur due to a
  // cancellation request by the market participant, system, or market operator.
  TRADE_STATE_CANCELED = 4;

  // RECALL: The trade has been recalled. This could be due to a system issue or
  // a request from the market participant or market operator.
  TRADE_STATE_RECALLED = 5;

  // RECALL_REQUESTED: A recall request for the trade has been submitted.
 TRADE_STATE_RECALL_REQUESTED = 6;

  // RECALL_REJECTED: The trade recall request was rejected.
  TRADE_STATE_RECALL_REJECTED = 7; 

  // APPROVAL: An approval has been requested.
  ORDER_STATE_APPROVAL_REQUESTED = 8;
}

Here is also an updated OrderStatus enum:

// Enum for the state of an order.
enum OrderState {
  // UNSPECIFIED: The order state is not known. This is usually the default
  // state of a newly created order object before any operations have been
  // applied.
  ORDER_STATE_UNSPECIFIED = 0;

  // PENDING: The order has been sent to the marketplace but has not yet been
  // confirmed. This can be due to awaiting validation or system processing.
  ORDER_STATE_PENDING = 1;

  // ACTIVE: The order has been confirmed and is open in the market.
  // It may be unfilled or partially filled.
  ORDER_STATE_ACTIVE = 2;

  // HIBERNATE: The order has been entered into the system but is not currently
  // exposed to the market. This could be due to certain conditions not yet
  // being met.
  ORDER_STATE_HIBERNATE = 3;

  // FILLED: The order has been completely filled and there are no remaining
  // quantities on the order.
  ORDER_STATE_FILLED = 4;

  // CANCELED: The order has been cancelled. This can occur due to a
  // cancellation request by the market participant, system, or market operator.
  ORDER_STATE_CANCELED = 5;

  // CANCEL_REQUESTED: A cancellation request for the order has been submitted
  // but the order is not yet removed from the order book.
  ORDER_STATE_CANCEL_REQUESTED = 6;

  // CANCEL_REJECTED: The order cancellation request was rejected, due to
  // it having already been filled or expired.
  ORDER_STATE_CANCEL_REJECTED = 7;

  // EXPIRED: The order has not been filled within the defined duration and has
  // expired.
  ORDER_STATE_EXPIRED = 8;

  // FAILED: The order submission failed and was unable to be placed on the
  // order book, usually due to a validation error or system issue.
  ORDER_STATE_FAILED = 9;
}

Use cases

No response

Alternatives and workarounds

Rename OrderState to just State

Additional context

No response

Update documentation on `PublicTrade` message

What's needed?

Updating the documentation.

Proposed solution

  message PublicTrade {
    // ID of the trade from the public order book.
    uint64 id = 1;

    // Delivery area code of the buy side.
    frequenz.api.common.v1.grid.DeliveryArea buy_delivery_area = 2;

    // Delivery area code of the sell side.
    frequenz.api.common.v1.grid.DeliveryArea sell_delivery_area = 3;

    // The delivery period for the contract.
    frequenz.api.common.v1.grid.DeliveryPeriod delivery_period = 4;

-   // UTC Timestamp of the last order update or matching.
-   google.protobuf.Timestamp modification_time = 5;
+   // UTC Timestamp of the trades execution time.
+   google.protobuf.Timestamp execution_time = 5;

-   // The limit price at which the contract is to be traded.
+   // The price at which the trade was executed.
    frequenz.api.common.v1.market.Price price = 6;

-   // The quantity of the contract being traded in MWh.
+   // The executed quantity of the contract traded.
    frequenz.api.common.v1.market.Energy quantity = 7;

    // Final state of the trade.
    OrderState state = 8;
  }

Use cases

No response

Alternatives and workarounds

No response

Additional context

No response

Split `OrderState.PENDING` in `UPDATE_PENDING` and `CREATE_PENDING`

What's needed?

Currently when an order has state PENDING it could be pending for creation or for update. For a naive strategy, knowing what caused the pending state is not needed, but looking into the future it might come in handy for some use cases with more complex trading strategies.

Proposed solution

Split OrderState.PENDING in UPDATE_PENDING and CREATE_PENDING

Use cases

More detailed information about their order status might be required to make informed decisions. For example if an application wants to implement "chain order" (he place a new order only if an update to an existing order is successfully executed), then the different pending states could come in handy.
Additionally this could facilitate debugging (if an order is stuck in state pending, it would be nice to know directly if it's creation pending or update pending).

Alternatives and workarounds

No response

Additional context

No response

Error in API Response Handling

What happened?

We have encountered an issue with our Python code where it is attempting to perform a decimal conversion on a field from the response of an API call, but the field is None. This has resulted in a decimal.InvalidOperation error.

Error Message:

amount=Decimal(price.amount.value),
^^^^^^^^^^^^^^^^^^^^^^^^^^
decimal.InvalidOperation: <class 'decimal.ConversionSyntax'>

What did you expect instead?

Handle the case that not all necessary fields are present in the API response before attempting any conversions or manipulations.

Affected version(s)

No response

Affected part(s)

I don't know (part:❓)

Extra information

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.