-
Notifications
You must be signed in to change notification settings - Fork 1
TradeProtocol Quickstart
This quickstart explains the steps required to get 2 simple agents trading with each other. This will involve making two simple countries that extend AbstractCountry, and adding these to the simulation.
In the first instance, an agent Peter will send a multicast message with an offer. There are functions in the AbstractCountry that encapsulates the low level TradeProtocol functions that is required to broadcast messages. These functions will be explained later on in the wiki.
Other agents will receive the offer message, and can show interest by initiating the Trade Protocol FSM. In this case, both Tom and Yiannis are interested.
Agent Peter can then decide which of the interested parties he will trade with. In this case, Peter has chosen to trade with Yiannis.
In this implementation, we will use two agents which extend AbstractCountry. The skeleton for any class which extends AbstractCountry is as follows:
public class Agent1 extends AbstractCountry{
public Scratch(...) {
super(...);
}
@Override
protected void processInput(Input input) {
/*
* This is where you will deal with incoming messages and
* decide if you would like to show interest in that offer
*/
}
@Override
public void YearlyFunction() {
}
@Override
public void SessionFunction() {
}
@Override
protected void initialiseCountry() {
}
@Override
protected void behaviour() {
// This is where you will multicast trade offers to other agents.
}
@Override
protected boolean acceptTrade(NetworkAddress from, Offer trade) {
/*
* This is where you implement logic to accept trades that you proposed
* that other countries have shown interest in.
* You can retrieve the properties of the negotiated offer itself from the trade argument,
* and the identity of your trading partner from the from argument.
*/
}
}Sending Offers
When you create a new offer, either to buy, sell, or ask for investment in your country, the offer is sent to all other countries in the current simulation, and they can choose whether or not to take you up or negotiate regarding your offer.
If you want to create an offer to sell carbon offset, call the following function.
broadcastSellOffer(quantity, unitCost);In this, quantity is how much carbon offset (in tons of carbon) you wish to sell. unitCost is the cost PER TON that you wish to sell at. An offer formatted like this:
broadcastSellOffer(10, 20);Is offering to sell 10 tons of carbon at $20 each, for a total value of $200.
Offering to buy carbon offset works in much the same way. You must call the following function.
broadcastBuyOffer(quantity, unitCost);The same logic applies to quantity and unitCost here as did for sell offers.
When you are creating a CDM (Clean Development Mechanism) offer, you are asking other countries to invest in you and pay for an amount of carbon absorption or reduction. To create a CDM offer, you call the following function.
broadcastInvesteeOffer(desiredOffset, investmentType);The desiredOffset variable is the amount, in tons of carbon, you want to offset. The investmentType variable tells other countries whether you plan to invest in carbon absorption or carbon reduction. It has the following possible values.
InvestmentType.ABSORB
InvestmentType.REDUCEThe cost associated with all of this, and therefore the amount of money other countries will have to invest, is calculated for you. As the offer creator, you do not need to work out that value.
Handling incoming messages
Agents handle incoming messages in the overridden processInput() method. This is where you will deal with incoming messages and decide if you would like to show interest in another agent's offer.
@Override
protected void processInput(Input in) {
if (this.tradeProtocol.canHandle(in)) {
this.tradeProtocol.handle(in);
}
else {
if(in instanceof Message){
try{
@SuppressWarnings("unchecked")
Message<OfferMessage> m = (Message<OfferMessage>) in;
OfferMessage o = m.getData();
if(!this.tradeProtocol
.getActiveConversationMembers()
.contains(m.getFrom())){
try {
this.tradeProtocol.offer(
m.getFrom(),
o.getOfferQuantity(),//get a chance to change quantity
//this one has been removed: o.getOfferUnitCost(),
o);
} catch (FSMException e) {
e.printStackTrace();
}
}
}catch(ClassCastException e){
logger.warn("Class cast exception");
logger.warn(e);
}
}
}
}Processing inputs has now been made a lot simpler. Functions have been provided which decodes the Input message for you to analyse and then agree to what the country has broadcasted. The above functions have been encapsulated in the following way:
@Override
protected void processInput(Input in) {
if (this.tradeProtocol.canHandle(in)) {
this.tradeProtocol.handle(in);
}else{
OfferMessage offerMessage = this.tradeProtocol.decodeInput(in); //function to decode Input in
/*analyse the offer*/
try {
this.tradeProtocol.respondToOffer(
this.tradeProtocol.extractNetworkAddress(in), //function to get who the message is from
offerMessage.getOfferQuantity(), //here you can modify the quantity
offerMessage);
} catch (IllegalArgumentException e1) {
logger.warn(e1);
} catch (FSMException e1) {
logger.warn(e1);
}
}
}In the modified function the agent will always respond to the offer it received. If it is interested in the offer then it uses the utility function respondToOffer() function in TradeProtocol which starts a conversation with the agent who broadcasted the message. Here the agent can decide to change the offer quantity (previously the agents were able to change both the quantity and unit cost).
It is recommended to use the later method but you can use the first method if you want to use the underlying low level functions.
Accepting/Rejecting other agents who agree to your offer
You will need to implement logic to accept/reject agents who have shown interest in your trade offer. You will do this by overriding the acceptTrade() method from AbstractCountry.
@Override
protected boolean acceptTrade(NetworkAddress from, Offer trade) {
// Your logic goes here. Returning true is accepting, false is rejecting.
return true;
}In this example, blindly returning true will accept all responses to any of your offers, regardless of what negotiation changes have been made.
Getting notifications whether the trade finished, rejected or failed
There are functions which has been added to AbstractCountry. These functions will let you as an initiator know whether the trade that you agreed to was successful, failed or if it was rejected. You have to override these functions if you want to get notified. The functions are as follows:
/**
* Override this method to get notified when trade was successful.
* This function is called for both initiator and responder when
* the trade was succesful.
* @param from
* @param offerMessage
*/
protected void tradeWasSuccessful(NetworkAddress from, OfferMessage offerMessage){
}
/**
* Override this method to get notified when trade failed.
* This function is called to notify both initiator and responder
* if somehow the trade has failed
* @param from
* @param offerMessage
*/
protected void tradeHasFailed(NetworkAddress from, OfferMessage offerMessage){
}
/**
* Override this method to get notified when trade was rejected
* This function is called to notify the initiator that the responder
* has rejected the trade that the initiator has offered.
* @param from
* @param offerMessage
*/
protected void tradeWasRejected(NetworkAddress from, OfferMessage offerMessage){
}There are many different ways of running the simulation. One quick easy (but hacky) way is just to add the following to Simulation.java. This is fine for testing, but will eventually need to be done more 'formally'.
For example:
AbstractParticipant p1 = new EUTest1(Random.randomUUID(), "Test1", "TS1", /* ... */);
AbstractParticipant p2 = new EUTest2(Random.randomUUID(), "Test2", "TS2", /* ... */);
s.addParticipant(p1);
s.addParticipant(p2);

