Re: Floating Markets

Scott Turner (srt@sun-dimas.aero.org)
Thu, 25 Aug 1994 10:39:21 -0700

>And I fully agree with other posters that [markets] is something that
>is really easy to screw up, and have devious players make piles
>of cash.

It's really not that hard to create a floating market. You'll find
attached to this posting a simulation of a floating market as I
proposed. It simulates 1 trade good and as many markets as you care
to create; it comes with 2 markets. Usage is fairly simple. There
are three commands:

buy <market> <qty>
sell <market> <qty>
end

The "end" command goes on to the next turn (replenishing the market
demand). End with EOF. Here's an example:

> M'lord? market
> MARKETS:
> A buying 20 at 20.000000.
> IC selling 20 at 5.000000.
> You have 500.000000 gold, 0 linen and are averaging 0.000000 profit/turn.
> buy IC 20 << user input ***
> MARKETS:
> A buying 20 at 20.000000.
> IC selling 0 at 5.000000.
> You have 400.000000 gold, 20 linen and are averaging 0.000000 profit/turn.
> sell A 20 << user input ***
> MARKETS:
> A buying 0 at 20.000000.
> IC selling 0 at 5.000000.
> You have 800.000000 gold, 0 linen and are averaging 0.000000 profit/turn.
> end << user input ***
> MARKETS:
> A buying 20 at 19.000000.
> IC selling 20 at 5.250000.
> You have 800.000000 gold, 0 linen and are averaging 300.000000 profit/turn.
> Unknown command, use 'buy', 'sell' or 'end'

Note that the prices float at the end of the turn. The maximum
profit/turn you can make in this 2 market system (in the long run) is
simply:

qty-available/turn * maximum-price-difference.

So, as the simulation comes to you, the maximum profit per turn is
20*15 = 300 gold/turn. Barring bugs, you simply cannot make more
money than that from this market system. And this is exactly the same
as the current situation in Olympia. So this system is no more
"abusable" than the existing system.

So what's the advantage of the floating market? Well, currently, to
maintain game balance, Rich has to keep either the maximum-price-
difference or the qty available on trade items fairly low. Otherwise,
there's the possibility that the markets will be abused -- someone
finds a gate between two markets with a large quantity of goods and a
high profit margin, and they quickly make ridiculous amounts of money.

With a floating market, the maximum price difference can be set much
higher. True, the first persons to trade at the high end are going to
make a lot (maybe obscene) profits. But then the trading itself will
drive down the price and therefore the profits. So there's an initial
incentive to start trading, and to open up new markets.

-- Scott T.

/*
* Compile with: gcc -o market market.c -lm
*
* MARKET
* Thu Aug 25 09:16:35 1994 -- Scott Turner
*
* Simple market simulator.
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <math.h>

/*
* Markets. We assume only one trade item, for simplicity's sake.
*
*/
struct MARKET {
char name[80]; /* Name of market */
int traded; /* Amount traded this turn. */
float value; /* Current market valuation of item. */
float max_value; /* Max valuation. */
float min_value; /* Min valuation. */
int demand; /* Current demand */
int min_demand; /* Min demand for item */
int max_demand; /* Max demand for item */
};

#define MAX_MARKETS 10
int num_markets = 0;
struct MARKET markets[MAX_MARKETS];

/*
* Trader's variables.
*
*/
float gold = 500.0;
int qty = 0;
int turns = 0;

void init_markets()
{
/*
* Aethelarn [A]
*
*/
strcpy(markets[num_markets].name,"A");
markets[num_markets].min_demand = -20;
markets[num_markets].max_demand = 20;
markets[num_markets].demand = 20;
markets[num_markets].min_value = 5.0;
markets[num_markets].max_value = 20.0;
markets[num_markets].value = 20.0;
num_markets++;

/*
* Imperial City [IC]
*
*/
strcpy(markets[num_markets].name,"IC");
markets[num_markets].min_demand = -20;
markets[num_markets].max_demand = 20;
markets[num_markets].demand = -20;
markets[num_markets].min_value = 5.0;
markets[num_markets].max_value = 20.0;
markets[num_markets].value = 5.0;
num_markets++;

};

/*
* FIND_MARKET
* Thu Aug 25 09:42:19 1994 -- Scott Turner
*
* Return a market given a market name.
*
*/
int find_market(char *name)
{
int i;
for(i=0;i<num_markets;i++)
if (!strncasecmp(name,markets[i].name,strlen(name))) return i;
return -1;
};

/*
* DO_BUY
* Thu Aug 25 09:39:30 1994 -- Scott Turner
*
* Buy an item.
*
*/
void do_buy(char *buf)
{
char where[80];
int num, market;

if (sscanf(buf,"buy %s %d",where,&num) != 2) {
fprintf(stderr,"Syntax error in buy command: buy <where> <num>\n");
return;
};

if (gold < 1.0) {
fprintf(stderr,"You have no gold to purchase linen.\n");
return;
};

if ((market = find_market(where)) == -1) {
fprintf(stderr,"Unknown market in buy command: %s\n",where);
return;
};

if (markets[market].demand > 0) {
fprintf(stderr,"The market in %s is not selling.\n",where);
return;
};

if (-(markets[market].demand + markets[market].traded) < num) {
fprintf(stderr,"The market in %s is only selling %d.\n",
where,
-(markets[market].demand + markets[market].traded));
num = -(markets[market].demand + markets[market].traded);
if (!num) return;
};

if (markets[market].value*num > gold) {
fprintf(stderr,"You only have enough gold to purchase %d units.\n",
floor(markets[market].value*num / gold));
num = (int) floor(markets[market].value*num / gold);
if (!num) return;
};

markets[market].traded += num;
gold -= num*markets[market].value;
qty += num;
};

/*
* DO_SELL
* Thu Aug 25 09:50:04 1994 -- Scott Turner
*
* Sell an item.
*
*/
void do_sell(char *buf)
{
char where[80];
int num, market;

if (sscanf(buf,"sell %s %d",where,&num) != 2) {
fprintf(stderr,"Syntax error in sell command: sell <where> <num>\n");
return;
};

if (qty < 1) {
fprintf(stderr,"You have no linen to sell.\n");
return;
};

if ((market = find_market(where)) == -1) {
fprintf(stderr,"Unknown market in sell command: %s\n",where);
return;
};

if (markets[market].demand < 0) {
fprintf(stderr,"The market in %s is not buying.\n",where);
return;
};

if ((markets[market].demand - markets[market].traded) > num) {
fprintf(stderr,"The market in %s is only buying %d.\n",
markets[market].demand - markets[market].traded);
num = markets[market].demand - markets[market].traded;
if (!num) return;
};

if (num > qty) {
fprintf(stderr,"You only have %d units to sell.\n",num);
num = qty;
};

markets[market].traded += num;
gold += num*markets[market].value;
qty -= num;
};

/*
* ADJUST_MARKETS
* Thu Aug 25 09:52:27 1994 -- Scott Turner
*
* Adjust the markets and increment the turn.
*
*/
void adjust_markets()
{
int i;

turns++;
for(i=0;i<num_markets;i++) {
if (markets[i].demand > 0) {
/*
* This market is buying.
*
*/
if (markets[i].traded) {
/*
* This market did business.
*
*/
markets[i].value *= 0.95;
if (markets[i].value < markets[i].min_value)
markets[i].value = markets[i].min_value;
} else {
markets[i].value *= 1.05;
if (markets[i].value > markets[i].max_value)
markets[i].value = markets[i].max_value;
};
} else {
/*
* This market is selling
*
*/
if (markets[i].traded) {
/*
* This market did business.
*
*/
markets[i].value *= 1.05;
if (markets[i].value > markets[i].max_value)
markets[i].value = markets[i].max_value;
} else {
markets[i].value *= 0.95;
if (markets[i].value < markets[i].min_value)
markets[i].value = markets[i].min_value;
};
};
markets[i].traded = 0;
};
};

main()
{
int num,i;
char buf[80];

init_markets();
while(!feof(stdin)) {
fprintf(stderr,"MARKETS:\n");
for(i=0;i<num_markets;i++)
if (markets[i].demand > 0) {
fprintf(stderr," %s buying %d at %f.\n",
markets[i].name, markets[i].demand-markets[i].traded,
markets[i].value);
} else {
fprintf(stderr," %s selling %d at %f.\n",
markets[i].name, -(markets[i].demand+markets[i].traded),
markets[i].value);
};
fprintf(stderr,"You have %f gold, %d linen and are averaging %f profit/turn.\n",
gold, qty, ((turns == 0) ? 0 : (gold-500.0)/turns));
bzero(buf,80);
gets(buf);
if (!strncasecmp(buf,"buy",3)) {
do_buy(buf);
} else if (!strncasecmp(buf,"sell",4)) {
do_sell(buf);
} else if (!strncasecmp(buf,"end",3)) {
adjust_markets();
} else {
fprintf(stderr,"Unknown command, use 'buy', 'sell' or 'end'\n");
};
};
};


Main Index  |  Olympia  |  Arena  |  PBM FAQ  |  Links