Price Change Mechanics

This is an overview of the mechanics governing the buy/sell prices of commodities in Europe. It’s a bit complex and there is some math involved. The game uses the term “yield” to refer to the commodities (horses, silver, rum, etc), so I’ll use that term here.
First I’ll go over the variables that determine the prices then I’ll explain the actual mechanics.

1. YieldBoughtTotal
For each type of yield, this value tracks the total amount of that yield that you’ve bought minus the total amount you’ve sold throughout the game. It starts off at zero. For example, if you sell 100 silver, the YieldBoughtTotal for silver goes down by 100. If you buy 300 horses, the YieldBoughtTotal for horses goes up by 300.

2. PriceChangeThreshold
For each multiple of this value that YieldBoughtTotal exceeds (positively or negatively) the price has a higher and higher chance of changing. It’s stored in AssetsXMLTerrainCIV4YieldInfos.xml. The threshold values are:[LIST]
[*]1500 for cloth, coats, rum, cigars
[*]1000 for food, lumber, cotton, fur, sugar, tobacco, ore
[*]600 for tools, guns, horses, goods
[*]100 for silver (really low!)
This value is modified by handicap percentage based on your difficulty level. The percentages are:[LIST]
[*]Pilgrim 200%
[*]Pioneer 120%
[*]Explorer 100%
[*]Conquistador 90%
[*]Governer 80%
[*]Patriot 70%
[*]Revolutionary 60%
[/LIST]These values are stored in AssetsXMLGameInfoCIV4HandicapInfo.xml

3. BuyPriceLow, BuyPriceHigh, SellPriceDifference
These values determine the starting price of the yield. The price Europe pays you for the yield, called the “buy price”, is simply a random number between BuyPriceLow and BuyPriceHigh, inclusive. The price you pay to Europe for the yield, called the “sell price”, is the buy price plus SellPriceDifference. The values are:[LIST]
[*]high, low, difference
[*]Food 0, 2, 8
[*]Lumber 0, 1, 3
[*]Silver 19, 19, 1
[*]Cotton 3, 5, 2
[*]Fur 4, 6, 2
[*]Sugar 4, 6, 2
[*]Tobacco 3, 5, 2
[*]Ore 2, 4, 3
[*]Cloth 8, 12, 1
[*]Coats 8, 12, 1
[*]Rum 8, 12, 1
[*]Cigars 8, 12, 1
[*]Tools 1, 2, 1
[*]Muskets 3, 5, 3
[*]Horses 1, 2, 1
[*]Trade Goods 1, 2, 1
Note again that the values are random; start up a game and you’ll see cloth, coats, rum and cigars all at different starting prices, even though they all have the same high/low/difference values. Also, these are not in any way limits on the maximum or minimum price. The maximum price for any yield is unbounded (I think), and the minimum price is always 1.

Again these values are stored in AssetsXMLTerrainCIV4YieldInfos.xml.

4. PriceCorrectionPercent
This value isn’t really a percent as it’s name says, but a multiplier that helps determines the chance of the price changing when YieldBoughtTotal exceeds PriceChangeThreshold.
The value is 5 for silver, and 1 for everything else. Stored in AssetsXMLTerrainCIV4YieldInfos.xml.

Now for the actual mechanics. Each turn the game determines a “target price” for each yield, and then does a random check to see if the actual price changes by 1 towards the target price (+1 if the target price is higher, -1 if the target price is lower). The actual price can only change by 1 each turn. The target price starts as a random number between BuyPriceLow and BuyPriceHigh. Then you add YieldBoughtTotal / PriceChangeThreshold (remember YieldBoughtTotal can be negative). The division is an integer division so decimal remainders are dropped. Next you take the absolute value of the difference between the target price and the actual price. and multiply it by PriceCorrectionPercent (5 for silver, and 1 for everything else; silver is volatile). This final value is the percent chance of a price change occurring.

If that seems complex, let’s do muskets as an example. The musket starting price is between 3 and 5, so we’ll say the game rolls a 4. Initially your YieldBoughtTotal is zero. PriceChangeThreshold for muskets is 600. Let’s look at what happens if you don’t buy or sell any muskets. Each turn the game computes the target price, which will be another random number between 3 and 5, let’s say it rolls a 5. YieldBoughtTotal is zero, so the target price isn’t modified. The difference between the target price (5) and the actual price (4) is 1, and the PriceCorrectionPercent for muskets is 1, so there is a 1% chance of a price change this turn. If a price change did occur, it would be +1 from 4 to 5, always towards the target price. Had you rolled a 3 for the target price, the price would have a 1% chance of going down by one this turn. The key here is that the price always has a small chance of fluctuating by a bit even if you don’t trade in that yield.

Now let’s say you go and buy 1000 muskets to fight the Spanish. Your YieldBoughtTotal is now 1000. The target price will now be computed as random[3, 5] + 1000/600, or random[3, 5] + 1 since decimals are truncated. Let’s say the actual price is still 4, and you roll a 5 on the random, then the target price would be 6. The difference is 6-4 = 2, so there would be a 2% chance of the price going up.

The spanish are really pressing you and you’ve had to buy 3000 more muskets. Your YieldBoughtTotal is now 1000+3000 = 4000. You’ve gotten lucky however, and the price is hasn’t gone up from 4. Now your target price is going to be random[3, 5] + 4000/600 = random[3, 5] + 6 = 9 to 11. Your chance of the price going up is between 5% and 7% each turn.

Let’s see how volatile silver is. The high and low are both 19, so the price doesn’t have any random variance. The PriceChangeThreshold is only 100(!!), and the PriceCorrectionPercent is 5 instead of the usual one, so your chance of change will be five times higher than it normally would be. Let’s say you sell 300 silver so your YieldBoughtTotal is -300 (remember it goes down when you sell). Then the target price is 19 – 300/100 = 16. The starting price is always 19, so the difference is 19-16 = 3%, but we multiply by PriceCorrectionPercent to get 5 * 3% = 15% of the price dropping! Silver is very volatile indeed.

Finally, the Mercantile trait of the Dutch: it simply cuts your trading volume in half. So if you sell 300 tobacco, it only counts as you having sold 150, so your YieldBoughtTotal goes up or down half as quickly. This means you can sell twice as many goods as the competition before you get the same price increase.

Here is C++ pseudo-code for process (the actual function is CvPlayer::doPrices() in CvGameCoreDLLCvPlayer.cpp).

for each yield
int newPrice = random(BuyPriceLow, BuyPriceHigh) + (YieldBoughtTotal / PriceChangeThreshold);

if (random(100) < PriceCorrectionPercent * abs(newPrice - currentPrice)) { newPrice = clamp(currentPrice - 1, newPrice, currentPrice + 1); setYieldBuyPrice(newPrice); } } [/CODE] [url=]Discuss this article on the forums[/url]