Skip to content

Commit

Permalink
Merge pull request #1589 from craig8/5.0rc-market
Browse files Browse the repository at this point in the history
Added market agents to the 5.0rc2
  • Loading branch information
craig8 authored Jan 4, 2018
2 parents 1c39285 + 5a3f3de commit 43fbb76
Show file tree
Hide file tree
Showing 85 changed files with 5,579 additions and 4 deletions.
18 changes: 18 additions & 0 deletions .github/issue_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
NOTE issues are for bugs/feature requests not support. Please ask at https://stackoverflow.com/questions/tagged/volttron for help

### Description of Issue
<!-- Describe your issue and tell us how to reproduce it (include any useful information). -->

### Affected Version

### Screenshots

#### Expected

#### Actual

### Steps to Reproduce

### Additional Details
<!-- Stack traces and/or log output -->

38 changes: 38 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Fixes # (issue)

## Type of change

Please delete options that are not relevant.

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update

# How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

- [ ] Test A
- [ ] Test B

**Test Configuration**:
* Firmware version:
* Hardware:
* Toolchain:
* SDK:

# Checklist:

- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream modules
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ applications
/config/
/docs/build/*
/docs/source/apidocs
volttron.log
2 changes: 2 additions & 0 deletions ci-integration/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ testdirs="services/core/VolttronCentral/tests services/core/VolttronCentralPlatf
#directories that must have their subdirectories split
splitdirs="services/core/*"

python bootstrap.py --market

echo "TestDirs"
for dir in $testdirs; do
echo "*********TESTDIR: $dir"
Expand Down
3 changes: 2 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,8 @@ def generate_apidoc(app):

# generate api-docs for examples
docs_subdir = os.path.join(apidocs_base_dir, "examples")
agent_dirs = glob(script_dir + "/../../examples/*/")
agent_dirs = glob(script_dir + "/../../examples/*/")
agent_dirs += glob(script_dir + "/../../examples/MarketAgents/*/")
run_apidoc(docs_subdir, agent_dirs, examples_excludes)

# generate api-docs for platform core and drivers
Expand Down
1 change: 1 addition & 0 deletions docs/source/core_services/service_agents/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Service Agents
failover/index
file_watch_publisher/index
platform/index
market_service/index
threshold/index
central_management/index
weather/index
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.. _MarketServiceAgent:

====================
Market Service Agent
====================

Introduction
============

The MarketServiceAgent implements a variation of a double-blind auction, in which each market participant bids
to buy or sell a commodity for a given price.

In contrast to other common implementations, participants do not bid single price-quantity pairs.
Instead, they bid a price-quantity curve, or “flexibility curve” into their respective markets.
Market participants may be both buyers in one market and sellers in another.
Settling of the market is a “single shot” process that begins with bidding that progresses from the bottom up
and concludes with a clearing of the markets from the top down. This is termed “single shot” because there is no
iteration required to find the clearing price or quantity at any level of the market structure.
Once the market has cleared, the process begins again for the next market interval, and
new bids are submitted based on the updated states of the agents.

Market Timing
-------------

The MarketServiceAgent is driven by the Director. The Director
drives the MarketServiceAgent through a timed loop. The Director has just a few parameters
that are configured by default with adequate values. They are:

1. The market_period with a default value of 5 minutes
2. The reservation_delay with a default value of 0 minutes
3. The offer_delay with a default value of 2 minutes

The timing loop works as follows:

* The market period begins.
* A request for reservations is published after the reservation delay.
* A request for offers/bids is published after the offer delay.
* The aggregate demand curve is published as soon all the buy offers are completed for the market.
* The aggregate supply curve is published as soon all the sell offers are completed for the market.
* The cleared price is published as soon as all bids have been received.
* Error messages are published when discovered and usually occur at the end of one of the delays.
* The cycle repeats.

How to Use the MarketServiceAgent
=================================

A given agent participates in one or more markets by inheriting from the
:ref:`base MarketAgent<Developing-Market-Agents>`.
The base MarketAgent handles all of the communication between the agent and the MarketServiceAgent.
The agent only needs to join each market with the
:py:meth:`join_market <volttron.platform.agent.base_market_agent.MarketAgent.join_market>`
method and then respond to the appropriate callback methods. The callback methods are described at the
:ref:`base MarketAgent<Developing-Market-Agents>`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
====================
Market Service Agent
====================

.. toctree::
:glob:
:maxdepth: 2

*
127 changes: 127 additions & 0 deletions docs/source/devguides/agent_development/Developing-Market-Agents.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
.. _Developing-Market-Agents:

===========================
Developing Market Agents
===========================

VOLTTRON provides a convenient base class for developing new market
agents. The base class automatically subscribes to all pertinent topics,
and spells out a simple interface for concrete implementation to
make a working Market Agent.

Markets are implemented by the Market Service Agent which is a core service agent.
The Market Service Agent publishes information on several topics to which the base
agent automatically subscribes. The base agent also provides all the methods you will
need to interact with the Market Service Agent to implment your market transactions.

MarketAgent
===========

All Market Agents must inherit from the MarketAgent class in
volttron.platform.agent.base_market_agent and call the following
method::
self.join_market(market_name, buyer_seller, reservation_callback, offer_callback, aggregate_callback, price_callback, error_callback)

This method causes the market agent to join a single market. If the agent wishes to participate in several
markets it may be called once for each market. The first argument is the name of the market to join and this name must
be unique across the entire volttron instance because all markets are implmented by a single market service agent for
each volttron instance. The second argument describes the role that this agent wished to play in this market.
The value is imported as::
from volttron.platform.agent.base_market_agent.buy_sell import BUYER, SELLER

Arguments 3-7 are callback methods that the agent may implement as needed for the agent's participation in the market.

The Reservation Callback
------------------------

.. code-block:: python
reservation_callback(self, timestamp, market_name, buyer_seller)
This method is called when it is time to reserve a slot in the market for the current market cycle.
If this callback is not registered a slot is reserved for every market cycle. If this callback is registered
it is called for each market cycle and returns True if a reservation is wanted and False if a reservation
is not wanted. The name of the market and the roll being played are provided so that a single callback can handle
several markets. If the agent joins three markets with the same reservation callback routine it will be called three
times with the appropriate market name and buyer/seller role for each call. The MeterAgent example
illustrates the use of this of this method and how to determine whether to make an offer when the reservation is
refused.
A market will only exist if there are reservations for at least one buyer or one seller.
If the market fails to achieve the minimum participation the error callback will be called.
If only buyers or only sellers make reservations any offers will be rejected
with the reason that the market has not formed.

The Offer Callback
------------------

.. code-block:: python
offer_callback(self, timestamp, market_name, buyer_seller)
If the agent has made a reservation for the market and a callback has been registered this callback is called.
If the agent wishes to make an offer at this time the market agent computes either a supply or
a demand curve as appropriate and offers the curve to the market service by calling the
:py:meth:`make_offer <volttron.platform.agent.base_market_agent.MarketAgent.make_offer>`
method.
The name of the market and the roll being played are provided so that a single callback can handle
several markets.
For each market joined either an offer callback, an aggregate callback, or a cleared price callback is required.

The Aggregate Callback
----------------------

.. code-block:: python
aggregate_callback(self, timestamp, market_name, buyer_seller, aggregate_curve)
When a market has received all its buy offers it calculates an aggregate demand curve.
When the market receives all of its sell offers it calculates an aggregate supply curve.
This callback delivers the aggregate curve to the market agent whenever the appropriate curve becomes available.
If the market agent wants to use this opportunity to make an offer on this or another market
it would do that using the
:py:meth:`make_offer <volttron.platform.agent.base_market_agent.MarketAgent.make_offer>`
method.
If the aggregate demand curve is received, obviously you could only make a supply offer on this market.
If the aggregate supply curve is received, obviously you could only make a demand offer on this market.
You can of course use this information to make an offer on another market. The example AHUAgent does this.
The name of the market and the roll being played are provided so that a single callback can handle
several markets.
For each market joined either an offer callback, an aggregate callback, or a cleared price callback is required.

The Price Callback
------------------

.. code-block:: python
price_callback(self, timestamp, market_name, buyer_seller, price, quantity)
This callback is called when the market clears.
If the market agent wants to use this opportunity to make an offer on this or another market
it would do that using the
:py:meth:`make_offer <volttron.platform.agent.base_market_agent.MarketAgent.make_offer>`
method.
Once the market has cleared you can't make an offer on that market.
You can of course use this information to make an offer on another market. The example AHUAgent does this.
The name of the market and the roll being played are provided so that a single callback can handle
several markets.
For each market joined either an offer callback, an aggregate callback, or a cleared price callback is required.

The Error Callback
------------------

.. code-block:: python
error_callback(self, timestamp, market_name, buyer_seller, error_code, error_message, aux)
This callback is called when an error occurs isn't in response to an RPC call.
The error codes are documented in::
from volttron.platform.agent.base_market_agent.error_codes import NOT_FORMED, SHORT_OFFERS, BAD_STATE, NO_INTERSECT

* NOT_FORMED - If a market fails to form this will be called at the offer time.
* SHORT_OFFERS - If the market doesn’t receive all its offers this will be called while clearing the market.
* BAD_STATE - This indicates a bad state transition while clearing the market and should never happen, but may be called while clearing the market.
* NO_INTERSECT - If the market fails to clear this would be called while clearing the market and an auxillary array will be included. The auxillary array contains comparisions between the supply max, supply min, demand max and demand min. They allow the market client to make determinations about why the curves did not intersect that may be useful.

The error callback is optional, but highly recommended.


Binary file added docs/source/images/example_market.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Loading

0 comments on commit 43fbb76

Please sign in to comment.