Putting together a simulation for the Mocaverse / Quidd Collaboration to identify the odds of winning an NFT

Thomaswnorton
8 min readJan 29, 2023

Lots of people on the Quidd discord were open about the arbitrage opportunity of Atari Quidd items once they were moved to OpenSea and sold as an NFT. This made the value of a 15-cent item (with 3 dollars of minting fees) worth between 9 and 5 dollars depending on the day. So plenty of people were taking part and making some nice pocket change. The reason that this opportunity occurred was due to each “Atari” help on OpenSea (rather than on Quidd) being worth one raffle ticket to the Mocaverse draw.

So, all the flipping was done I elected to hold a single ticket, for two reasons. If one of the tickets were somehow worth a fortune, then I would kick myself. It turns out, comparatively, they are with a “floor price” (look at me being all technical) of 30 dollars or around ten times the Atari Quidd item cost. Secondly, I was wondering If I could win one of the Mocaverse items and use it as my Twitter PFP (and totally not because certain people keep using a dolphin NFT as a PFP and getting jealous). But what are the odds of winning with one NFT and is the rational expected value worth running your luck on the draw or is the “correct” thing to do is cash out now?

Thankfully with the blockchain, we have a lot of public information that we can infer the odds and thus the value of the ticket for the draw.

Distribution of Users Soon after drop that I used in this article

With these two stats, we can start making some estimates of the distribution of items:-

But this information is not enough to start simulating to work out what the odds of someone in each group getting an item. Instead, we need to know how many items they each contain and for the banded items a guestimate to the approximate average number of items for the people in the band. After some excel modelling, I managed to get to this:-

However, this has an obvious issue, 4 is not 2 or 3 items. In addition, I am not that happy with the 50 figure either as it is at the top of the band. I assume that 50 plus figure is an underestimation of the average as the top 100 leader board all have over a hundred. But as an approximation, it will have to do, mostly as I have no idea how to refine it other than guess different combinations of random numbers! At least this was a formulaic calculation! Also, as items are bought and sold on the market, they will be slight fluctuations that already mean I will be at least a little wrong!

With this, I wrote a java program to run 5000 simulations of the draw (code posted at the bottom of the article) in runs of 2500. From this, I can see how many of the draws that the first person in each group “wins” an NFT and that is an inference of the odds.

So, what does this mean? Each row of the table is a different simulation of a draw, and where there is a TRUE, the raffle ticket is still waiting to be pulled so no NFT for you. Where it says FALSE you are a happy bunny with a shiny new NFT as your ticket has been removed (along with all the other raffle tickets that you hold). With this, we can approximate the odds as:-

In my 5000 simulations, not one time did the test user miss out when they were holding 50 or 96 tickets. In the real draw someone might be that unlucky but it’s an approximation. And I am pleased with my 19.80% chance. So with an implied odds of 19.80% and the current “value” of the ticket being, 30 dollars if you value the NFT at over 151 dollars you should keep the ticket, if not then sell up. I do, So I am holding out hope that I am in the 20% not the 80% of single ticket holders!

EDIT / UPDATE : So, I incorrectly Assumed that with 8888 NFT’s there would be 8888 drawings. On twitter Mocaverse have said that it will be 1500 draws, I guess after the constant giveaways on twitter? This will change the odds considerably! Most of the chance that us one tickets have is when the big-ticket holders win and their other tickets get out the pool, the number of tickets still in will drop quickly. So, I have changed the code (labelled code 2 below) and got the following results from 1000 simulations:

New Odds for holders in each group. Not as pretty reading!

Much worse odds for everyone. So for a single ticket with the new odds of around 1.5% and the same 30 dollars of the ticket, the NFT needs to be valued at around 2000 dollars. Up to you if that’s still worth holding out on the draw!

Java Code bodged together to make the simulation. (Yes this should be commented!)

package com.mycompany.mocastat;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;


public class NewClass {
public static void main(String[] args){

int x = 0;

while(x < 2500){
NewClass NC = new NewClass();
NC.makedataset();
NC.runsim();
NC.testcases();
x = x + 1;
}
}

public List<String> racecardlist = new ArrayList<>();



private void makedataset() {
//test case and all the other cases of only holding 1
int x = 0;
racecardlist.add("TestCase1");
while(x < 10558){
racecardlist.add("1" + x);
x = x + 1;
}

//holding 4
x = 0;
int y = 0;
while(y < 4){
racecardlist.add("TestCase2");
y = y + 1;
}
while(x < 2687){
y = 0;
while(y < 4){
racecardlist.add("4" + x);
y = y + 1;
}
x = x + 1;
}

//holding 8
x = 0;
y = 0;
while(y < 8){
racecardlist.add("TestCase3");
y = y + 1;
}
while(x < 4416){
y = 0;
while(y < 8){
racecardlist.add("8" + x);
y = y + 1;
}
x = x + 1;
}

//holding 21
x = 0;
y = 0;
while(y < 21){
racecardlist.add("TestCase4");
y = y + 1;
}
while(x < 960){
y = 0;
while(y < 21){
racecardlist.add("21" + x);
y = y + 1;
}
x = x + 1;
}

//holding 50
x = 0;
y = 0;
while(y < 50){
racecardlist.add("TestCase5");
y = y + 1;
}
while(x < 384){
y = 0;
while(y < 50){
racecardlist.add("50" + x);
y = y + 1;
}
x = x + 1;
}

//holding 96
x = 0;
y = 0;
while(y < 96){
racecardlist.add("TestCase6");
y = y + 1;
}
while(x < 192){
y = 0;
while(y < 96){
racecardlist.add("96" + x);
y = y + 1;
}
x = x + 1;
}

}

private void runsim() {
int x = 0;
Random random = new Random();
while(x < 8888){
int testno = random.nextInt(racecardlist.size());
RemoveElement(testno);
x = x + 1;
}
}

private void RemoveElement(int testno) {
String element = racecardlist.remove(testno);
int x = testno - 100;
int y = testno + 100;

if(y > racecardlist.size()){
y = racecardlist.size();
}
if(x < 0){
x = 0;
}

while(x < y){
if(x < racecardlist.size()){
if(racecardlist.get(x).equals(element)){
racecardlist.remove(x);
}else{
x = x + 1;
}
}else{
break;
}
}

}

private void testcases() {
int x = 0;
boolean test1 = false;
boolean test2 = false;
boolean test3 = false;
boolean test4 = false;
boolean test5 = false;
boolean test6 = false;

while(x < racecardlist.size()){
if(racecardlist.get(x).contains("TestCase1")){
test1 = true;
}else if(racecardlist.get(x).contains("TestCase2")){
test2 = true;
}else if(racecardlist.get(x).contains("TestCase3")){
test3 = true;
}else if(racecardlist.get(x).contains("TestCase4")){
test4 = true;
}else if(racecardlist.get(x).contains("TestCase5")){
test5 = true;
}else if(racecardlist.get(x).contains("TestCase6")){
test6 = true;
}
x = x + 1;
}

System.out.println(test1 + "," + test2 + "," + test3 + "," + test4 + "," + test5 + "," + test6);
racecardlist = null;
}

}

Updated Java Code (basically two lines different but got to be transparent!)


package com.mycompany.mocastat;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;


public class NewClass {
public static void main(String[] args){

int x = 0;

while(x < 1000){
NewClass NC = new NewClass();
NC.makedataset();
NC.runsim();
NC.testcases();
x = x + 1;
}
}

public List<String> racecardlist = new ArrayList<>();



private void makedataset() {
//test case and all the other cases of only holding 1
int x = 0;
racecardlist.add("TestCase1");
while(x < 10558){
racecardlist.add("1" + x);
x = x + 1;
}

//holding 4
x = 0;
int y = 0;
while(y < 4){
racecardlist.add("TestCase2");
y = y + 1;
}
while(x < 2687){
y = 0;
while(y < 4){
racecardlist.add("4" + x);
y = y + 1;
}
x = x + 1;
}

//holding 8
x = 0;
y = 0;
while(y < 8){
racecardlist.add("TestCase3");
y = y + 1;
}
while(x < 4416){
y = 0;
while(y < 8){
racecardlist.add("8" + x);
y = y + 1;
}
x = x + 1;
}

//holding 21
x = 0;
y = 0;
while(y < 21){
racecardlist.add("TestCase4");
y = y + 1;
}
while(x < 960){
y = 0;
while(y < 21){
racecardlist.add("21" + x);
y = y + 1;
}
x = x + 1;
}

//holding 50
x = 0;
y = 0;
while(y < 50){
racecardlist.add("TestCase5");
y = y + 1;
}
while(x < 384){
y = 0;
while(y < 50){
racecardlist.add("50" + x);
y = y + 1;
}
x = x + 1;
}

//holding 96
x = 0;
y = 0;
while(y < 96){
racecardlist.add("TestCase6");
y = y + 1;
}
while(x < 192){
y = 0;
while(y < 96){
racecardlist.add("96" + x);
y = y + 1;
}
x = x + 1;
}

}

private void runsim() {
int x = 0;
Random random = new Random();
while(x < 1500){
int testno = random.nextInt(racecardlist.size());
RemoveElement(testno);
x = x + 1;
}
}

private void RemoveElement(int testno) {
String element = racecardlist.remove(testno);
int x = testno - 100;
int y = testno + 100;

if(y > racecardlist.size()){
y = racecardlist.size();
}
if(x < 0){
x = 0;
}

while(x < y){
if(x < racecardlist.size()){
if(racecardlist.get(x).equals(element)){
racecardlist.remove(x);
}else{
x = x + 1;
}
}else{
break;
}
}

}

private void testcases() {
int x = 0;
boolean test1 = false;
boolean test2 = false;
boolean test3 = false;
boolean test4 = false;
boolean test5 = false;
boolean test6 = false;

while(x < racecardlist.size()){
if(racecardlist.get(x).contains("TestCase1")){
test1 = true;
}else if(racecardlist.get(x).contains("TestCase2")){
test2 = true;
}else if(racecardlist.get(x).contains("TestCase3")){
test3 = true;
}else if(racecardlist.get(x).contains("TestCase4")){
test4 = true;
}else if(racecardlist.get(x).contains("TestCase5")){
test5 = true;
}else if(racecardlist.get(x).contains("TestCase6")){
test6 = true;
}
x = x + 1;
}

System.out.println(test1 + "," + test2 + "," + test3 + "," + test4 + "," + test5 + "," + test6);
racecardlist = null;
}

}

--

--

Thomaswnorton

A place for the musings of a data and technology obsessed millennial. Expect topics as varied as Stock Market, Horse Racing and K-Pop