R broker - Pyosch/powertac-server GitHub Wiki

up

There is considerable interest in a Power TAC broker that can be programmed in the R language. R is an interpreted language implemented in C++ and Fortran. It can be integrated with Java through a "native interface," but Java classes are quite different in structure than the data types available in R. This page intends to outline some basic goals and principles, and explore possible approaches.

Architectural goals

  • The R programmer should see incoming data as vectors, lists, and data frames, and not have to pick apart java structures element-by-element.
  • The R programmer should be able to develop a working broker using a standard interactive IDE. This means that during development, the messages for a timeslot should arrive, and the server should pause while the developer inspects the data, analyzes it, and implements/modifies the R code. The developer should then be able to formulate and send responses back to the server and allow the next timeslot to proceed.
  • A sample R broker should handle all the message types, and should perform at least as well as the existing sample Java broker.

Possible approaches

rJava/JRI

This is a low-level R-to-Java interface, and a callback interface from Java to R. The rJava package is used to implement an interactive graphing system for R using the Java awt GUI library. R code can call arbitrary methods as long as the correct arg types can be constructed, but the set of types usable in the interface seems quite limited. So if you have a few hundred TariffTransaction instances to analyze, you would have to read off individual fields from the Java objects and construct R lists or some other structure before you could use the information. It seems that R code would have to be written to translate each Java message type into something R can work with. This will be a major effort.

XML stream

All the incoming and outgoing data from a Power TAC broker is serialized as XML messages by the XStream package. The translation between XML and Java objects is the responsibility of XStream, as directed by annotations in the code. But there appears to be a very decent XML library for R, called "XML". If the raw XML messages are handed directly to the R process, they could be sorted by type and directly turned into a data frame for each message type. In turn, the R process can compose frames that can be turned into XML and passed back to the Java back end. One challenge might be formatting the outgoing messages correctly.

If we are to use this approach, we need a way to pass individual XML messages to the R process, and from the R process back to the server. This might be done using rJava, but that might require some very large character arrays. Two other approaches that might be tried:

  • Run R and Java in separate processes, connected by a pair of fifos (named pipes).
  • Use the Redis key-value database (through the rredis library) as an interchange buffer.

The separate-process model could be implemented with the fork() call on Linux/Mac/Android systems, but not Windows. Probably something like it could be found or implemented for Windows. It would have the advantage of putting the R process firmly in control, and would allow the Java process to be managed by maven. On the Java side, communication is through stdin and stdout.

The separate-process model would not allow the R programmer access to features of broker-core such as customer and tariff repositories and the time service. These would not be difficult to re-implement for R. More important is the object-identifier protocol by which objects that arrive in the server from different brokers can be indexed by id values, which are guaranteed not to overlap. This is accomplished by sending each broker an id-prefix value at login time, which is added to sequential id values generated by the broker. If the R process is to be responsible for composing the XML messages, it will have to generate and assign proper id values.

Broker behaviors

This section briefly describes the behaviors that a broker must implement. For each behavior, there is incoming data, possibly some behavior, and possibly a response. Much of the detail is in the specification, and the message types are all defined in the common module in packages org.powertac.common and org.powertac.common.msg. The xml messages shown here are extracted from the trace log of the sample broker running a solo game in development mode.

Start of Game

Broker login will presumably be handled by the existing Java code, so there is no need for the R code to see those messages. At SOG (start-of-game), the broker first receives a login-accept message that gives the id prefix value:

<broker-accept prefix="2" key="zf4eb8" serverTime="1449508032196"/>

Next, it receives several messages that describe the game environment. The first is the Competition instance, containing some details of clock setup, the identities of competing brokers, and a list of customer instances and their properties:

<competition id="0" name="t2b" pomId="1.3.1-SNAPSHOT" timeslotLength="60" bootstrapTimeslotCount="336" bootstrapDiscardedTimeslots="24" timeslotsOpen="24" deactivateTimeslotsAhead="1" minimumOrderQuantity="0.01" timezoneOffset="-6" latitude="45" simulationRate="720" simulationModulo="3600000">
  <description></description>
  <simulationBaseTime>
    <iMillis>1255132800000</iMillis>
  </simulationBaseTime>
  <broker>default broker</broker>
  <broker>Sample</broker>
  <customer id="3840" name="b12" population="1" powerType="BATTERY_STORAGE" customerClass="SMALL" controllableKW="-40.0
" upRegulationKW="-40.0" downRegulationKW="40.0" storageCapacity="90.0" multiContracting="false" canNegotiate="false"/>
  <customer id="4096" name="HighIncome-2_10" population="1" powerType="ELECTRIC_VEHICLE" customerClass="SMALL" controllableKW="-6.6" upRegulationKW="-6.6" downRegulationKW="6.6" storageCapacity="24.0" multiContracting="false" canNegotiate="false"/>
  <customer id="4099" name="HighIncome-2_11" population="1" powerType="ELECTRIC_VEHICLE" customerClass="SMALL" controllableKW="-6.6" upRegulationKW="-6.6" downRegulationKW="6.6" storageCapacity="24.0" multiContracting="false" canNegotiate="false"/>
  <customer id="3332" name="DowntownOffices" population="30" powerType="CONSUMPTION" customerClass="SMALL" controllableKW="0.0" upRegulationKW="0.0" downRegulationKW="0.0" storageCapacity="0.0" multiContracting="true" canNegotiate="false"/>
  ...
</competition>

Next is a set of name-value pairs that describe details of the simulation configuration. Note that the names are package.class, so if you go to the Java source, you can see that each of these is mapped to a variable or method tagged with @ConfigurableValue. The Java sources are in the modules distribution-utility, balancing-market, auctioneer, and accounting:

<properties>
  <property name="distributionutility.distributionUtilityService.useMeterFee" value="true"/>
  <property name="balancemkt.balancingMarketService.rmPremium" value="2.0"/>
  <property name="distributionutility.distributionUtilityService.mSmall" value="-0.015"/>
  <property name="distributionutility.distributionUtilityService.stdCoefficient" value="1.2"/>
  <property name="auctioneer.auctionService.sellerSurplusRatio" value="0.5"/>
  <property name="balancemkt.balancingMarketService.settlementProcess" value="static"/>
  <property name="distributionutility.distributionUtilityService.balancingCost" value="-0.00437436129385552"/>
  <property name="tariffmarket.tariffMarketService.publicationFee" value="-4347.774248121315"/>
  <property name="distributionutility.distributionUtilityService.defaultSpotPrice" value="-50.0"/>
  <property name="tariffmarket.tariffMarketService.revocationFee" value="-154.62122614659103"/>
  <property name="distributionutility.distributionUtilityService.useCapacityFee" value="true"/>
  <property name="distributionutility.distributionUtilityService.assessmentInterval" value="168"/>
  <property name="balancemkt.balancingMarketService.balancingCost" value="-0.00437436129385552"/>
  <property name="distributionutility.distributionUtilityService.distributionFee" value="0.0"/>
  <property name="balancemkt.balancingMarketService.pMinusPrime" value="-1.0E-6"/>
  <property name="distributionutility.distributionUtilityService.feePerPoint" value="-180.0"/>
  <property name="balancemkt.balancingMarketService.defaultSpotPrice" value="-50.0"/>
  <property name="distributionutility.distributionUtilityService.pPlusPrime" value="1.0E-6"/>
  <property name="balancemkt.balancingMarketService.pPlusPrime" value="1.0E-6"/>
  <property name="accounting.accountingService.bankInterest" value="0.1025742002067474"/>
  <property name="auctioneer.auctionService.defaultMargin" value="0.2"/>
  <property name="distributionutility.distributionUtilityService.mLarge" value="-0.05"/>
  <property name="distributionutility.distributionUtilityService.pMinusPrime" value="-1.0E-6"/>
  <property name="distributionutility.distributionUtilityService.useTransportFee" value="false"/>
  <property name="auctioneer.auctionService.defaultClearingPrice" value="40.0"/>
</properties>

Next, for each customer, is a record of their energy consumption/production during the 2-week bootstrap period, one value for each timeslot in the bootstrap period (nominally 360 timeslots). Here is part of the data for CentervilleHomes; note that the sign indicates the direction of power flow -- negative is toward the customer, positive is toward the broker:

<customer-bootstrap-data id="938315" customerName="CentervilleHomes" powerType="CONSUMPTION">
<netUsage>-12391.35,-10114.47,-10140.86,-11078.46,-11878.63,-14476.89,-13162.94,-14258.63,-14123.5,-14169.36,-13705.84,-14090.340000000002,...</netUsage>
</customer-bootstrap-data>

Next is a record of energy trading and prices in the wholesale market during the bootstrap period, one entry per timeslot; again, the signs indicate the direction of energy and money flow from a broker's viewpoint, and prices are per-MWh:

<market-bootstrap-data id="938607">
  <mwh>40.95884800000005,40.328089861100096,43.10454465350664,51.85378530783136,54.49313841123366,60.92061090600654,44.605544455502276,59.36643951972485,...</mwh>
  <marketPrice>-124.12755392710862,-17.709759037038168,-34.78745750315098,-218.34365565481434,-81.44333206309733,-205.4500215178752,-20.06859471666362,-33.03741812546915</marketPrice>
</market-bootstrap-data>

Note that prices are quite volatile in the first few timeslots; they tend to settle down a bit later in the bootstrap period.

Next is weather reports for each timeslot during the bootstrap period:

<weather-report id="626" currentTimeslot="24" temperature="11.3" windSpeed="3.0" windDirection="250.0" cloudCover="0.5"/>
2127 INFO  core.BrokerMessageReceiver: onMessage(String) - received message:
<weather-report id="627" currentTimeslot="25" temperature="11.7" windSpeed="3.0" windDirection="250.0" cloudCover="0.125"/>
2127 INFO  core.BrokerMessageReceiver: onMessage(String) - received message:
<weather-report id="628" currentTimeslot="26" temperature="10.8" windSpeed="2.0" windDirection="240.0" cloudCover="1.0"/>
2128 INFO  core.BrokerMessageReceiver: onMessage(String) - received message:
<weather-report id="629" currentTimeslot="27" temperature="11.5" windSpeed="2.0" windDirection="230.0" cloudCover="1.0"/>

Note that the first timeslot in this set is 24, because data from the first 24h of the bootstrap period is discarded.

The bootstrap data ends with the final timeslot-update message of the bootstrap period:

<timeslot-update id="4650" firstEnabled="361" lastEnabled="384">
  <postedTime>
    <iMillis>1256428800000</iMillis>
  </postedTime>
</timeslot-update>

Then the game starts:

<sim-start>
  <start>
    <iMillis>1458236044364</iMillis>
  </start>
</sim-start>

Per-timeslot

A few seconds later, the first timeslot of the sim starts with a weather report and a 24h forecast:

<timeslot-update id="4651" firstEnabled="361" lastEnabled="384">
  <postedTime>
    <iMillis>1256428800000</iMillis>
  </postedTime>
</timeslot-update>
<weather-report id="2" currentTimeslot="360" temperature="13.2" windSpeed="7.0" windDirection="240.0" cloudCover="0.125"/>
<weather-forecast id="602" currentTimeslot="360">
  <prediction id="26" forecastTime="1" temperature="13.3" windSpeed="6.07" windDirection="236.0" cloudCover="0.0"/>
  <prediction id="27" forecastTime="2" temperature="14.4" windSpeed="6.07" windDirection="231.0" cloudCover="0.0"/>
  <prediction id="28" forecastTime="3" temperature="13.2" windSpeed="5.98" windDirection="218.0" cloudCover="0.467"/>
  ...
</weather-forecast>

In the first timeslot, the broker receives the tariffs published by the default broker:

<tariff-spec id="1878" minDuration="0" powerType="CONSUMPTION" signupPayment="0.0" earlyWithdrawPayment="0.0" periodicPayment="0.0">
  <broker>default broker</broker>
  <rates>
    <rate id="1879" tariffId="1878" weeklyBegin="-1" weeklyEnd="-1" dailyBegin="-1" dailyEnd="-1" tierThreshold="0.0" fixed="true" minValue="-0.5" maxValue="0.0" noticeInterval="0" expectedMean="0.0" maxCurtailment="0.0">
      <rateHistory/>
    </rate>
  </rates>
</tariff-spec>
<tariff-spec id="1881" minDuration="0" powerType="PRODUCTION" signupPayment="0.0" earlyWithdrawPayment="0.0" periodicPayment="0.0">
  <broker>default broker</broker>
  <rates>
    <rate id="1882" tariffId="1881" weeklyBegin="-1" weeklyEnd="-1" dailyBegin="-1" dailyEnd="-1" tierThreshold="0.0" fixed="true" minValue="0.01" maxValue="0.0" noticeInterval="0" expectedMean="0.0" maxCurtailment="0.0">
      <rateHistory/>
    </rate>
  </rates>
</tariff-spec>
<tariff-spec id="1884" minDuration="0" powerType="STORAGE" signupPayment="0.0" earlyWithdrawPayment="0.0" periodicPayment="0.0">
  <broker>default broker</broker>
  <rates>
    <rate id="1885" tariffId="1884" weeklyBegin="-1" weeklyEnd="-1" dailyBegin="-1" dailyEnd="-1" tierThreshold="0.0" fixed="true" minValue="-0.5" maxValue="0.0" noticeInterval="0" expectedMean="0.0" maxCurtailment="0.0">
      <rateHistory/>
    </rate>
    <regulation-rate id="1887" tariffId="1884" response="MINUTES" upRegulationPayment="0.01" downRegulationPayment="-0.5"/>
  </rates>
</tariff-spec>

Note that the STORAGE tariff includes a regulation-rate in addition to the standard 0.50/kWh consumption rate. Note also that signs in tariff specifications are given from the customer's viewpoint, so the customer pays 0.50 for down-regulation, and is paid 0.01 for up-regulation.

Next we see the end-of-timeslot messages including distribution and bank transactions, followed by current cash position and the overall distribution report:

<distribution-tx id="5610" postedTimeslot="360" kWh="0.0" nSmall="0" nLarge="0" charge="0.0">
  <broker>Sample</broker>
</distribution-tx>
<bank-tx id="5613" postedTimeslot="360" amount="0.0">
  <broker>Sample</broker>
</bank-tx>
<cash id="5614" postedTimeslot="360" balance="0.0">
  <broker>Sample</broker>
</cash>
<ts-done timeslotIndex="360"/>

That's the end of timeslot 360. Subsequent timeslots typically have much more information, after the broker has published some tariffs, done some trading in the wholesale market, and possibly issued balancing-orders for its contracted storage and/or interruptible-consumption capacity.

Timeslot 361 is the first opportunity to publish tariffs; tariffs to be published must be sent to the server before the start of ts 361. Here are the tariffs published by the sample broker:

<tariff-spec id="200000002" minDuration="0" powerType="CONSUMPTION" signupPayment="0.0" earlyWithdrawPayment="0.0" periodicPayment="-0.95">
  <broker>Sample</broker>
  <rates>
    <rate id="200000003" tariffId="200000002" weeklyBegin="-1" weeklyEnd="-1" dailyBegin="-1" dailyEnd="-1" tierThreshold="0.0" fixed="true" minValue="-0.21273967908743271" maxValue="0.0" noticeInterval="0" expectedMean="0.0" maxCurtailment="0.0">
      <rateHistory/>
    </rate>
  </rates>
</tariff-spec>
<tariff-spec id="200000005" minDuration="0" powerType="INTERRUPTIBLE_CONSUMPTION" signupPayment="0.0" earlyWithdrawPayment="0.0" periodicPayment="-0.95">
  <broker>Sample</broker>
  <rates>
    <rate id="200000006" tariffId="200000005" weeklyBegin="-1" weeklyEnd="-1" dailyBegin="-1" dailyEnd="-1" tierThreshold="0.0" fixed="true" minValue="-0.1489177753612029" maxValue="0.0" noticeInterval="0" expectedMean="0.0" maxCurtailment="0.4">
      <rateHistory/>
    </rate>
  </rates>
</tariff-spec>
<tariff-spec id="200000008" minDuration="0" powerType="THERMAL_STORAGE_CONSUMPTION" signupPayment="0.0" earlyWithdrawPayment="0.0" periodicPayment="0.0">
  <broker>Sample</broker>
  <rates>
    <regulation-rate id="200000011" tariffId="200000008" response="MINUTES" upRegulationPayment="-0.17870133043344347" downRegulationPayment="0.05956711014448116"/>
    <rate id="200000009" tariffId="200000008" weeklyBegin="-1" weeklyEnd="-1" dailyBegin="-1" dailyEnd="-1" tierThreshold="0.0" fixed="true" minValue="-0.1489177753612029" maxValue="0.0" noticeInterval="0" expectedMean="0.0" maxCurtailment="0.0">
      <rateHistory/>
    </rate>
  </rates>
</tariff-spec>
<tariff-spec id="200000012" minDuration="0" powerType="ELECTRIC_VEHICLE" signupPayment="0.0" earlyWithdrawPayment="0.0" periodicPayment="0.0">
  <broker>Sample</broker>
  <rates>
    <regulation-rate id="200000015" tariffId="200000012" response="MINUTES" upRegulationPayment="-0.17870133043344347" downRegulationPayment="0.05956711014448116"/>
    <rate id="200000013" tariffId="200000012" weeklyBegin="-1" weeklyEnd="-1" dailyBegin="-1" dailyEnd="-1" tierThreshold="0.0" fixed="true" minValue="-0.1489177753612029" maxValue="0.0" noticeInterval="0" expectedMean="0.0" maxCurtailment="0.0">
      <rateHistory/>
    </rate>
  </rates>
</tariff-spec>
<tariff-spec id="200000016" minDuration="0" powerType="SOLAR_PRODUCTION" signupPayment="0.0" earlyWithdrawPayment="0.0" periodicPayment="-0.475">
  <broker>Sample</broker>
  <rates>
    <rate id="200000017" tariffId="200000016" weeklyBegin="-1" weeklyEnd="-1" dailyBegin="-1" dailyEnd="-1" tierThreshold="0.0" fixed="true" minValue="0.1445028117257196" maxValue="0.0" noticeInterval="0" expectedMean="0.0" maxCurtailment="0.0">
      <rateHistory/>
    </rate>
  </rates>
</tariff-spec>
<tariff-spec id="200000019" minDuration="0" powerType="WIND_PRODUCTION" signupPayment="0.0" earlyWithdrawPayment="0.0" periodicPayment="-0.475">
  <broker>Sample</broker>
  <rates>
    <rate id="200000020" tariffId="200000019" weeklyBegin="-1" weeklyEnd="-1" dailyBegin="-1" dailyEnd="-1" tierThreshold="0.0" fixed="true" minValue="0.1445028117257196" maxValue="0.0" noticeInterval="0" expectedMean="0.0" maxCurtailment="0.0">
      <rateHistory/>
    </rate>
  </rates>
</tariff-spec>
<tariff-spec id="200000022" minDuration="0" powerType="BATTERY_STORAGE" signupPayment="0.0" earlyWithdrawPayment="0.0" periodicPayment="0.0">
  <broker>Sample</broker>
  <rates>
    <regulation-rate id="200000025" tariffId="200000022" response="MINUTES" upRegulationPayment="-0.17870133043344347" downRegulationPayment="0.05956711014448116"/>
    <rate id="200000023" tariffId="200000022" weeklyBegin="-1" weeklyEnd="-1" dailyBegin="-1" dailyEnd="-1" tierThreshold="0.0" fixed="true" minValue="-0.1489177753612029" maxValue="0.0" noticeInterval="0" expectedMean="0.0" maxCurtailment="0.0">
      <rateHistory/>
    </rate>
  </rates>
</tariff-spec>

The broker does no trading in this timeslot, although it could; there is no reason not to anticipate some subscriptions.

For each tariff received by the tariff market, the broker receives a confirmation message:

<tariff-status id="7173" tariffId="200000002" updateId="200000002" status="success">
  <broker>Sample</broker>
</tariff-status>
...

The next timeslot begins with a timeslot-update message, a weather report, and a 24h forecast:

<timeslot-update id="7186" firstEnabled="362" lastEnabled="385">
  <postedTime>
    <iMillis>1256432400000</iMillis>
  </postedTime>
</timeslot-update>
<weather-report id="3" currentTimeslot="361" temperature="13.0" windSpeed="6.0" windDirection="240.0" cloudCover="0.0"/>
<weather-forecast id="603" currentTimeslot="361">
  <prediction id="50" forecastTime="1" temperature="12.9" windSpeed="6.07" windDirection="236.0" cloudCover="0.0"/>
  <prediction id="51" forecastTime="2" temperature="14.1" windSpeed="6.07" windDirection="221.0" cloudCover="0.332"/>
  <prediction id="52" forecastTime="3" temperature="12.7" windSpeed="3.98" windDirection="218.0" cloudCover="1.0"/>
  <prediction id="53" forecastTime="4" temperature="12.1" windSpeed="5.52" windDirection="208.0" cloudCover="0.085"/>
  <prediction id="54" forecastTime="5" temperature="13.1" windSpeed="6.36" windDirection="207.0" cloudCover="0.103"/>
  <prediction id="55" forecastTime="6" temperature="14.7" windSpeed="5.5" windDirection="215.0" cloudCover="0.015"/>
  <prediction id="56" forecastTime="7" temperature="15.6" windSpeed="6.26" windDirection="209.0" cloudCover="0.0"/>
  <prediction id="57" forecastTime="8" temperature="16.7" windSpeed="7.13" windDirection="206.0" cloudCover="0.302"/>
  <prediction id="58" forecastTime="9" temperature="15.9" windSpeed="6.85" windDirection="214.0" cloudCover="0.544"/>
  <prediction id="59" forecastTime="10" temperature="15.3" windSpeed="7.75" windDirection="212.0" cloudCover="0.809"/>
  <prediction id="60" forecastTime="11" temperature="15.2" windSpeed="8.04" windDirection="223.0" cloudCover="0.974"/>
  <prediction id="61" forecastTime="12" temperature="15.2" windSpeed="8.03" windDirection="228.0" cloudCover="0.674"/>
  <prediction id="62" forecastTime="13" temperature="14.1" windSpeed="7.98" windDirection="230.0" cloudCover="0.271"/>
  <prediction id="63" forecastTime="14" temperature="12.7" windSpeed="6.84" windDirection="218.0" cloudCover="0.02"/>
  <prediction id="64" forecastTime="15" temperature="11.9" windSpeed="7.05" windDirection="220.0" cloudCover="0.05"/>
  <prediction id="65" forecastTime="16" temperature="11.9" windSpeed="6.79" windDirection="222.0" cloudCover="0.446"/>
  <prediction id="66" forecastTime="17" temperature="11.9" windSpeed="5.4" windDirection="205.0" cloudCover="0.954"/>
  <prediction id="67" forecastTime="18" temperature="11.3" windSpeed="6.66" windDirection="217.0" cloudCover="0.93"/>
  <prediction id="68" forecastTime="19" temperature="10.9" windSpeed="6.85" windDirection="220.0" cloudCover="0.707"/>
  <prediction id="69" forecastTime="20" temperature="10.3" windSpeed="6.92" windDirection="224.0" cloudCover="0.947"/>
  <prediction id="70" forecastTime="21" temperature="10.2" windSpeed="5.9" windDirection="226.0" cloudCover="0.57"/>
  <prediction id="71" forecastTime="22" temperature="10.0" windSpeed="5.95" windDirection="216.0" cloudCover="0.958"/>
  <prediction id="72" forecastTime="23" temperature="9.7" windSpeed="7.27" windDirection="228.0" cloudCover="0.829"/>
  <prediction id="73" forecastTime="24" temperature="10.0" windSpeed="6.37" windDirection="226.0" cloudCover="0.964"/>
</weather-forecast>

Next is market clearing information. The sample broker did not issue any orders prior to the start of this timeslot, so the only wholesale market info is the orderbooks of uncleared bids/asks and cleared qty/price, one for each of the 24 cleared timeslots:

<orderbook id="7193" timeslot="361" clearingPrice="34.20227438010324">
  <dateExecuted>
    <iMillis>1256432400000</iMillis>
  </dateExecuted>
  <bid limitPrice="-0.25556075043479004" mWh="1956.4819681791555"/>
  <ask limitPrice="28.5018953167527" mWh="-4.103752283876093"/>
  <ask limitPrice="40.46175116069227" mWh="-5.391359001466194"/>
  <ask limitPrice="52.45272846145758" mWh="-4.838545541559274"/>
  <ask limitPrice="64.29082907680542" mWh="-4.473681357079465"/>
  <ask limitPrice="76.3623135659059" mWh="-4.085901330126614"/>
  ...
</orderbook>
<trade id="7242" timeslot="361" executionPrice="34.20227438010324" executionMWh="34.49194653189253">
  <dateExecuted>
    <iMillis>1256432400000</iMillis>
  </dateExecuted>
</trade>
...

Next is the balance-report, showing the net imbalance for the timeslot after the customer models have run:

<balance-report id="8823" netImbalance="1600.2757110625826" timeslotIndex="361"/>

Since timeslot 361 is a tariff-publication timeslot, the broker receives details of all newly-published tariffs, including its own:

<tariff-spec id="200000008" minDuration="0" powerType="THERMAL_STORAGE_CONSUMPTION" signupPayment="0.0" earlyWithdrawPayment="0.0" periodicPayment="0.0">
  <broker>Sample</broker>
  <rates>
    <regulation-rate id="200000011" tariffId="200000008" response="MINUTES" upRegulationPayment="-0.17870133043344347" downRegulationPayment="0.05956711014448116"/>
    <rate id="200000009" tariffId="200000008" weeklyBegin="-1" weeklyEnd="-1" dailyBegin="-1" dailyEnd="-1" tierThreshold="0.0" fixed="true" minValue="-0.1489177753612029" maxValue="0.0" noticeInterval="0" expectedMean="0.0" maxCurtailment="0.0">
      <rateHistory/>
    </rate>
  </rates>
</tariff-spec>
...

For each published tariff, there is a tariff-transaction showing the publication fee:

<tariff-tx id="7172" postedTimeslot="360" txType="PUBLISH" customerCount="0" kWh="0.0" charge="-4347.774248121315">
  <broker>Sample</broker>
  <tariffSpec>200000002</tariffSpec>
</tariff-tx>
...

Customers are notified of published tariffs, and may change their subscriptions. For each subscription change among the broker's tariffs, there will be a SIGNUP or a WITHDRAW tariff-transaction:

<tariff-tx id="8885" postedTimeslot="361" txType="SIGNUP" customerCount="1" kWh="0.0" charge="-0.0">
  <broker>Sample</broker>
  <customerInfo>3675</customerInfo>
  <tariffSpec>200000005</tariffSpec>
</tariff-tx>
<tariff-tx id="9715" postedTimeslot="361" txType="SIGNUP" customerCount="10" kWh="0.0" charge="-0.0">
  <broker>Sample</broker>
  <customerInfo>2612</customerInfo>
  <tariffSpec>200000005</tariffSpec>
</tariff-tx>
<tariff-tx id="9725" postedTimeslot="361" txType="SIGNUP" customerCount="20000" kWh="0.0" charge="-0.0">
  <broker>Sample</broker>
  <customerInfo>3323</customerInfo>
  <tariffSpec>200000002</tariffSpec>
</tariff-tx>
...

This is followed by the normal end-of-timeslot messages.

Now that the broker has some subscriptions, it can look up the consumption records of each customer and estimate how much energy to buy or sell for the next 24 timeslots. For each timeslot, it may issue one or more orders specifying a timeslot, a quantity, and (optionally) a limit price:

<order id="200000026" timeslot="362" mWh="37.519833585457">
  <broker>Sample</broker>
</order>
<order id="200000027" timeslot="363" mWh="44.43617335190041" limitPrice="-70.0">
  <broker>Sample</broker>
</order>
<order id="200000028" timeslot="364" mWh="47.32309339802727" limitPrice="-45.160524870026215">
  <broker>Sample</broker>
</order>
...

At the start of the next timeslot, after the weather and market updates, the broker receives some market-transaction and market-position messages:

<market-tx id="10980" postedTimeslot="362" price="-186.30910847197092" mWh="5.173736192112546" timeslot="362">
  <broker>Sample</broker>
</market-tx>
<market-posn id="10981" timeslot="362" bal="37.519833585457">
  <broker>Sample</broker>
</market-posn>
...

Note that there can be many market-tx messages for a given timeslot, since the market creates a transaction for each trade between an individual bid and ask, and does not attempt to consolidate them by timeslot.

Now that customers have subscriptions to the broker's tariffs, we see PERIODIC, CONSUME and PRODUCE transactions showing the customer, the energy consumed or produced, and the overall charge credited to the broker's bank account. Quantities are specified from the broker's viewpoint.

<tariff-tx id="12209" postedTimeslot="362" txType="CONSUME" customerCount="10" kWh="-3.85" charge="0.8190477644866159">
  <broker>Sample</broker>
  <customerInfo>1893</customerInfo>
  <tariffSpec>200000002</tariffSpec>
</tariff-tx>
<tariff-tx id="12210" postedTimeslot="362" txType="PERIODIC" customerCount="10" kWh="0.0" charge="0.3958333333333333">
  <broker>Sample</broker>
  <customerInfo>1893</customerInfo>
  <tariffSpec>200000002</tariffSpec>
</tariff-tx>
<tariff-tx id="12261" postedTimeslot="362" txType="PRODUCE" customerCount="50" kWh="2538.87" charge="-366.8738536060777">
  <broker>Sample</broker>
  <customerInfo>3397</customerInfo>
  <tariffSpec>200000019</tariffSpec>
</tariff-tx>
<tariff-tx id="12262" postedTimeslot="362" txType="PERIODIC" customerCount="50" kWh="0.0" charge="0.9895833333333334">
  <broker>Sample</broker>
  <customerInfo>3397</customerInfo>
  <tariffSpec>200000019</tariffSpec>
</tariff-tx>
...

Now that the broker is delivering or receiving energy from customers, there is also a balancing-transaction in each timeslot, and the distribution-transaction shows the hourly meter charges:

<balance-tx id="12598" postedTimeslot="362" kWh="2604.4139396176324" charge="23.447283200427005">
  <broker>Sample</broker>
</balance-tx>
<distribution-tx id="12600" postedTimeslot="362" kWh="0.0" nSmall="57491" nLarge="9" charge="-862.815">
  <broker>Sample</broker>
</distribution-tx>

Some time later, the broker decides to issue some balancing-orders in order to take advantage of the storage and interruptible-consumption capacity is has under contract:

<balancing-order id="200000266" tariffId="200000008" exerciseRatio="1.0" price="0.17870133043344347">
  <broker>Sample</broker>
</balancing-order>
<balancing-order id="200000267" tariffId="200000008" exerciseRatio="-1.0" price="-0.05956711014448116">
  <broker>Sample</broker>
</balancing-order>
<balancing-order id="200000268" tariffId="200000012" exerciseRatio="1.0" price="0.17870133043344347">
  <broker>Sample</broker>
</balancing-order>
<balancing-order id="200000269" tariffId="200000012" exerciseRatio="-1.0" price="-0.05956711014448116">
  <broker>Sample</broker>
</balancing-order>
<balancing-order id="200000270" tariffId="200000022" exerciseRatio="1.0" price="0.17870133043344347">
  <broker>Sample</broker>
</balancing-order>
<balancing-order id="200000271" tariffId="200000022" exerciseRatio="-1.0" price="-0.05956711014448116">
  <broker>Sample</broker>
</balancing-order>
<balancing-order id="200000272" tariffId="200000005" exerciseRatio="0.5" price="-0.13402599782508262">
  <broker>Sample</broker>
</balancing-order>

Note that the exercise ratios are +1 and -1 for the storage types, and 0.5 for the interruptible-consumption type (although the up-regulation ratios should probably be 2.0 for the battery-storage types). With these orders in place (they last until revoked or superseded), we start to see balancing-controls exercised in later timeslots due to operation of the balancing market:

<balancing-control id="40585" tariffId="200000012" timeslotIndex="372" kwh="-396.93644178619485" payment="33.36468220891421">
  <broker>Sample</broker>
</balancing-control>
<balancing-control id="40646" tariffId="200000022" timeslotIndex="372" kwh="-1200.0" payment="100.86657317360356">
  <broker>Sample</broker>
</balancing-control>

This pattern continues for the duration of the game. When the broker receives the sim-end message, the game is over:

<sim-end/>

Architectural questions and decisions

This section is intended to pose questions and explore alternatives. It may be helpful to refer to the sample-broker javadocs while reading this material.

Repositories

Assuming the primary interface between the broker-core and the R application code is XML, that means there is no need to un-marshal (xml->java) most of the incoming messages, nor to marshal outgoing messages. But if we do not generate the Java objects, we cannot use the various repositories that come with the Power TAC domain model. These are in the common module in the common.repo package, including BrokerRepo, CustomerRepo, OrderbookRepo, TariffRepo, TimeslotRepo, WeatherForecastRepo, WeatherRepo. At the least, these can return lists of objects and translate numeric ID values into the corresponding Java objects. Some do more than that: CustomerRepo can return customers with a given PowerType, TariffRepo keeps track of the Rates, RegulationRates, and BalancingOrders associated with Tariffs and associates Tariffs with Brokers and with PowerTypes, TimeslotRepo can translate a timeslot index to a time or vice-versa.

Most likely this functionality can be easily implemented in R.

⚠️ **GitHub.com Fallback** ⚠️