Incentive

Time to time, I give advice to my friends for the bid they would put on Tehran Commodity Exchange (IME). The auctions are structured as follows: there is a minimum price, fixed supply and maximum price change of 10 percent. Then the ones who put the highest price will get the commodity at the price they demand till supply meets demand. So on average lowest winning bit is lower than highest price.

The models I wrote for this matter are generally based on nth price common value auctions and I use some model averaging on them. They normally predict lowest bid or weighted adjusted mean bid with RMSE of .5 percent. So on average there is a 1-2% gain in that transaction.

Last week, given the data, I ran the models. To my surprise for LLD209 and LD0075 shown estimates that were more than 10 percent of maximum allowed price. The result of competition among bidders, supported the results. Observing this, it seemed to me that the market was cornered. Pretty beautiful thing to be witnessed. I was excited :))

Given the fact that it seemed that the market is cornered, I thought about the conditioned that it could happen. My thought is considering this thing as a game theoretic question.

Here are the situation that yield to market being cornered:

  • Following Feb IRRUSD rate was surging. The price of petrochemicals in Tehran have very high correlation to their international prices in USD terms.

  • Commodity traders and consumers have bought considerable amounts of LD and LLD. They tried to first enjoy the rise in the price, second avoid buying at higher expected prices.

  • During third week of March to 1st week of April, consumers of LLD and LD are at national new year holidays and subsequently demand for LD and LLD reduces to lowest amount. So most of the inventory of LLD and LD remain the same.

  • And the last and most crucial one. While till third week of April IRRUSD was around 49000, the government banned the transactions and reduced the price to 42000. As a result most of the traders of LD and LLD faced substantial losses.

set up

Since this is just for my curiosity, I try to simplify the solutions and try to be concise.

As I observed, there is an strictly dominant strategy for players. They are N players, of which k are doing speculative trades. Due to lack of productions in previous weeks of auctions I simplify and assume that N is equal to k. Each player has three choices, do not increase the bid from base price, bid at average increase rate, and bid the maximum available amount. ( Actually as I said before I consider bidding as nth price common value auction, I try to not make things more complicated than necessary).Based on market price and demand of bidders the player decides on his/her choice. Generally, putting the difference of market price and auction price aside, In case of bidding at base price, demand is less than supply. If the average winning bid increases at less than 10 percent, then demand amount of winning bid meet supply. If 10 percent increase in average bids occur, then demand needs to be at least equal to supply.

Let see summary of bids in the cases that they have increased from base price, and let see the tail of data. The data has been subset to the date after 2016-08-01. I saw small changes in structure around that time, thought I have not check it with structural break tests.

library(XLConnect)

## Loading required package: XLConnectJars

## XLConnect 0.2-12 by Mirai Solutions GmbH [aut],
##   Martin Studer [cre],
##   The Apache Software Foundation [ctb, cph] (Apache POI, Apache Commons
##     Codec),
##   Stephen Colebourne [ctb, cph] (Joda-Time Java library),
##   Graph Builder [ctb, cph] (Curvesapi Java library)

## http://www.mirai-solutions.com ,
## http://miraisolutions.wordpress.com

library(xts)

## Loading required package: zoo

## 
## Attaching package: 'zoo'

## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric

library(leaps)
library(MuMIn)
library(openxlsx)

## 
## Attaching package: 'openxlsx'

## The following objects are masked from 'package:XLConnect':
## 
##     loadWorkbook, mergeCells, saveWorkbook

path_LLD_PS<- "C:/Users/msdeb/OneDrive/data/petrochemicals/IME_LLDPE_clean.xlsx"

data.IME<- readWorksheetFromFile(path_LLD_PS, 
                                 sheet=1)
data.IME<-data.IME[, c(2:9,12)]
data.IME$DATE<- as.Date(data.IME$DATE,  "%Y/%m/%d")
data.IME<- as.xts( data.IME[,-9], order.by = data.IME$DATE)
data.IME<- data.IME[ -which(data.IME$supply == 0),]
data.IME<- data.IME[ -which(data.IME$HIGH == data.IME$BASEp),]
#data.IME<- data.IME[ -which(is.na(data.IME$HIGH)),]
# 2017/08/29
subIME<- data.IME["2016-08-01::"]


path<- "C:/Users/msdeb/OneDrive/data/petrochemicals"
#path<- "C:/Users/msdeb/OneDrive/data/petrochemicals"
setwd(path)
data.IME0075<-read.xlsx("IME_LDPE_clean.xlsx", sheet = 3, colNames = TRUE)
data.IME0075<- data.IME0075[, c(2:9,12)]
data.IME0075[,8]<- as.numeric(data.IME0075[,8])
data.IME0075$DATE<- as.Date(data.IME0075$DATE,  "%Y/%m/%d")
data.IME0075<- as.xts( data.IME0075[,-9], order.by = data.IME0075$DATE)
if ( sum(data.IME0075$supply == 0, na.rm = TRUE)>0){
  data.IME0075<- data.IME0075[ -which(data.IME0075$supply == 0),]  
}
if ( sum(data.IME0075$demand/data.IME0075$supply <= 1, na.rm = TRUE)>0){
  data.IME0075<- data.IME0075[ -which(data.IME0075$demand/data.IME0075$supply <= 1),]  
}
if ( sum(data.IME0075$HIGH == data.IME0075$BASEp, na.rm = TRUE)>0){
  data.IME0075<- data.IME0075[ -which(data.IME0075$HIGH == data.IME0075$BASEp),]
}

subIME0075<- data.IME0075["2016-08-01::"]

print("LLD209")

## [1] "LLD209"

tail(subIME[,1:6])

##              LOW adjCLOSE  HIGH supply BASEp demand
## 2018-02-06 51529    51729 52909   4994 50214   7964
## 2018-02-27 51893    52029 52666   1496 50488   2684
## 2018-03-06 51353    51419 52159   4400 51353   4598
## 2018-03-07 52290    52453 53699   3300 50214   5126
## 2018-04-17 50328    50328 50328   4400 45753  14674
## 2018-04-24 50262    50262 50262   3300 45693  30074

summary( subIME[,1:6])

##      Index                 LOW           adjCLOSE          HIGH      
##  Min.   :2016-08-23   Min.   :38171   Min.   :38269   Min.   :38765  
##  1st Qu.:2016-12-04   1st Qu.:40167   1st Qu.:40376   1st Qu.:41383  
##  Median :2017-05-29   Median :43009   Median :43232   Median :44010  
##  Mean   :2017-06-04   Mean   :43664   Mean   :43887   Mean   :44762  
##  3rd Qu.:2017-11-22   3rd Qu.:45658   3rd Qu.:45923   3rd Qu.:47127  
##  Max.   :2018-04-24   Max.   :52290   Max.   :52453   Max.   :53699  
##      supply         BASEp           demand     
##  Min.   : 250   Min.   :37766   Min.   : 1390  
##  1st Qu.:2200   1st Qu.:39041   1st Qu.: 4534  
##  Median :3300   Median :42081   Median : 5786  
##  Mean   :3158   Mean   :42147   Mean   : 6361  
##  3rd Qu.:4400   3rd Qu.:43531   3rd Qu.: 7359  
##  Max.   :5500   Max.   :51353   Max.   :30074

incr.bid209<- subIME$HIGH / subIME$BASEp
colnames(incr.bid209)<- "incr.bid.ratio"
summary(incr.bid209[ " ::2018-04-01"])

##      Index            incr.bid.ratio 
##  Min.   :2016-08-23   Min.   :1.005  
##  1st Qu.:2016-11-30   1st Qu.:1.042  
##  Median :2017-04-28   Median :1.067  
##  Mean   :2017-05-24   Mean   :1.061  
##  3rd Qu.:2017-11-12   3rd Qu.:1.083  
##  Max.   :2018-03-07   Max.   :1.100

mean.incr.bid209<- mean(incr.bid209[ " ::2018-04-01"])
print("mean increase bid till holidays-209")

## [1] "mean increase bid till holidays-209"

mean.incr.bid209

## [1] 1.060584

print("LD0075")

## [1] "LD0075"

tail(subIME0075[,1:6])

##              LOW adjCLOSE  HIGH supply BASEp demand
## 2018-02-13 53800    53919 54189   1000 52865   1540
## 2018-03-06 52535    52603 52739   1500 52534   1750
## 2018-03-13 54369    54810 57248   1000 52044   3460
## 2018-03-27 55031    55228 55899   1000 54134   1590
## 2018-04-04 55388    55789 57279   1000 54134   1900
## 2018-04-17 51735    51735 51735   1500 47032   7330

summary( subIME0075[,1:6])

##      Index                 LOW           adjCLOSE          HIGH      
##  Min.   :2016-08-16   Min.   :40275   Min.   :40909   Min.   :41419  
##  1st Qu.:2017-01-13   1st Qu.:43455   1st Qu.:43807   1st Qu.:44494  
##  Median :2017-07-04   Median :44909   Median :45042   Median :45377  
##  Mean   :2017-06-16   Mean   :46029   Mean   :46226   Mean   :46804  
##  3rd Qu.:2017-10-27   3rd Qu.:47823   3rd Qu.:47980   3rd Qu.:48849  
##  Max.   :2018-04-17   Max.   :55388   Max.   :55789   Max.   :57279  
##      supply         BASEp           demand     
##  Min.   : 500   Min.   :38308   Min.   : 1090  
##  1st Qu.:1000   1st Qu.:41194   1st Qu.: 1840  
##  Median :1000   Median :43971   Median : 2510  
##  Mean   :1149   Mean   :44497   Mean   : 2958  
##  3rd Qu.:1500   3rd Qu.:47158   3rd Qu.: 3225  
##  Max.   :2000   Max.   :54134   Max.   :11210

incr.bid0075<- subIME0075$HIGH / subIME0075$BASEp
colnames(incr.bid0075)<- "incr.bid.ratio"
summary(incr.bid0075[ " ::2018-04-01"])

##      Index            incr.bid.ratio 
##  Min.   :2016-08-16   Min.   :1.004  
##  1st Qu.:2016-12-27   1st Qu.:1.025  
##  Median :2017-06-25   Median :1.050  
##  Mean   :2017-06-07   Mean   :1.053  
##  3rd Qu.:2017-10-17   3rd Qu.:1.080  
##  Max.   :2018-03-27   Max.   :1.100

mean.incr.bid0075<- mean(incr.bid0075[ " ::2018-04-01"])
print("mean increase bid till holidays-0075")

## [1] "mean increase bid till holidays-0075"

mean.incr.bid0075

## [1] 1.052724

Price of the commodity in market is loosely equal to average bid price times 9.262 percent VAT and omissions, plus the amount they pay to the people who has the right to buy at exchange( bidding is limited to the ones who has a production facility, they get a 500IRR per kilo to let others use their right- this is not an absolutely legal act.), plus the amount they pay for transportation from petrochemical facilities to Tehran which is 950 IRR in this case and finally a mark-up they add per kilo which is loosely 1000IRR. So the prices for LLD209 and LD0075 could be computed as follows:

# LLD209
mrkup = 1000
# Base price for bidding
baseP = subIME$BASEp[ dim(subIME)[1]]
colnames(baseP)<- "baseP"
baseP

##            baseP
## 2018-04-24 45693

# Tax and commisions
tax.com.m = 1.09262
# commision to owner of the right to buy commodity
tax.com.c = 500
# Transportation costs
trnsp = 950
# Base price of previous auction
baseP.prv.auc = subIME$BASEp[ dim(subIME)[1]-3]
colnames(baseP.prv.auc)<- "baseP.prv.auc"
baseP.prv.auc

##            baseP.prv.auc
## 2018-03-06         51353

# market price based on bidding at base price
Pbc = baseP*tax.com.m + tax.com.c + trnsp + mrkup
colnames(Pbc)<- "Pbc"
Pbc

##                 Pbc
## 2018-04-24 52375.09

# Market price on which the inventory been acquired
P.prv.auc = baseP.prv.auc*tax.com.m + tax.com.c + trnsp + mrkup
colnames(P.prv.auc)<- "P.prv.auc"
P.prv.auc

##            P.prv.auc
## 2018-03-06  58559.31

# market price based on average increase in bids
Pc = (baseP*mean.incr.bid209)*tax.com.m + tax.com.c + trnsp + mrkup
colnames(Pc)<- "Pc"
Pc

##                  Pc
## 2018-04-24 55399.77

# Market price based on maximum bid available
Pcor = (baseP*1.1)*tax.com.m + tax.com.c + trnsp + mrkup
colnames(Pcor)<- "Pcor"
Pcor

##                Pcor
## 2018-04-24 57367.59

# LD0075

baseP0075 = subIME0075$BASEp[ dim(subIME0075)[1]]
colnames(baseP0075)<- "baseP0075"
baseP0075 

##            baseP0075
## 2018-04-17     47032

# Base price of previous auction
baseP.prv.auc0075  = subIME0075$BASEp[ dim(subIME0075)[1]-3]
colnames(baseP.prv.auc0075)<- "baseP.prv.auc0075"
baseP.prv.auc0075 

##            baseP.prv.auc0075
## 2018-03-13             52044

# market price based on bidding at base price
Pbc0075  = baseP0075 *tax.com.m + tax.com.c + trnsp + mrkup
colnames(Pbc0075)<- "Pbc0075"
Pbc0075 

##            Pbc0075
## 2018-04-17 53838.1

# Market price on which the inventory been acquired
P.prv.auc0075  = baseP.prv.auc0075 *tax.com.m + tax.com.c + trnsp + mrkup
colnames(P.prv.auc0075)<- "P.prv.auc0075"
P.prv.auc0075 

##            P.prv.auc0075
## 2018-03-13      59314.32

# market price based on average increase in bids
Pc0075  = (baseP0075 *mean.incr.bid0075 )*tax.com.m + tax.com.c + trnsp + mrkup
colnames(Pc0075)<- "Pc0075"
Pc0075 

##              Pc0075
## 2018-04-17 56547.48

# Market price based on maximum bid available
Pcor0075  = (baseP0075 *1.1)*tax.com.m + tax.com.c + trnsp + mrkup
colnames(Pcor0075)<- "Pcor0075"
Pcor0075 

##            Pcor0075
## 2018-04-17 58976.91

Simplified payoff that I consider here is consisted of two part. Here I assumed that players are identical and the amount they buy is minimum one truckload, that is 20 tons. We also assume that there exist a total speculative inventory “Inv” in the market and that is equally distributed among “k” trader. First part is the amount the player pays for reacquiring commodities, and second part is the amount of change in value of its inventory:

minimum position = 20000 Kg payoff in case of bidding at base price:

−(Pbc − mrkup)*20000 + Pbc * Inv/k − P.prv.auc * Inv/k

s.*t. : k x  20 <= supply

payoff in case of an increase in bid equal to average increase:

−(Pc − mrkup)*20000 + Pc * Inv/k − P.prv.auc * Inv/k

s.*t. : k x  20 = supply

payoff in case of bidding at maximum available price:

−(Pcor − mrkup) x (supply/k x  20000) x 20000  +Pcor xInv/k − P.prv.auc x Inv/k

The last payoff, takes the fact that in case of equal bids, the supply would be divided equally to bidders into account. As we will see this ratio has a enormous effect on the cost of cornering market.

For having a strictly dominant strategy, the second payoff should be strictly larger than first one. Also the third term should be strictly larger than second term.

Inv/k > ((Pc − Pbc)*20000)/(Pc − Pbc)

Inv/k > ( − (Pc − mrkup)*20000 + (Pcor − mrkup)*(supply/20000 * k)*20000)/(Pcor − Pc)

The first inequality reduces to Inv/k being bigger than minimum position which is 20 Tons.

If we neglect the mark-up term, the second inequality would be:

Inv/k > 20000 * (Pcor * (supply/k * 20000)) − Pc)/(Pcor − Pc)

It means if the supply over aggregate demand being low enough, then the inequality is holding even for very small per player inventory. In other words, in this design and by these assumption, market will be cornered.

Let see what is the amount of minimum per player inventory given the data:

# Minimum per trader position for LLD209 in order that 2nd inequality holds
supply<- 3300 # Ton
k = 30074 / 20 # Ton
 min.per.Inv<- ((-(Pc - mrkup) * 20000) + (Pcor - mrkup) *
                  ((supply / (20000* k))*20000))/(Pcor- Pc)
 colnames(min.per.Inv)<- "min.per.Inv"
min.per.Inv

##            min.per.Inv
## 2018-04-24   -552829.5

# Minimum per trader position for LD0075 in order that 2nd inequality holds
 supply<- 1500 # Ton
 k = 7330 / 20 # Ton
 min.per.Inv0075<- ((-(Pc0075 - mrkup) * 20000) + (Pcor0075 - mrkup) *
                      ((supply / (20000* k))*20000))/(Pcor0075- Pc0075)
  colnames(min.per.Inv0075)<- "min.per.Inv0075"
 min.per.Inv0075

##            min.per.Inv0075
## 2018-04-17       -457190.2

Oh, these are pretty fascinating results :))

Given the data, strictly dominant strategy will be choosen.

Conclusion

It seems that under special circumstances that total speculative inventory is high enough, decision to cornering market is strictly dominant strategy, regardless of previous price.

If inventories of speculative traders meet above criterion there is incentive to bid at highest available price. So by the time that inventories get consumed for producing products, cornering the market could continue. A decrease in prices due to importing of commodities from gulf countries could change the assumptions, yet giveno new regulations in Forex market, it does not seem to happen.

Please inform me about your feedback, I will be deeply grateful for that :)
For disclaimer please see about page.