Skip to content

Commit

Permalink
TCI
Browse files Browse the repository at this point in the history
  • Loading branch information
TheColdIce committed Nov 9, 2023
1 parent 01daa62 commit 837c6bb
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 77 deletions.
12 changes: 11 additions & 1 deletion AMLsim/paramFiles/10K_accts/conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@
"std_amount": 100,
"mean_amount_sar": 1000,
"std_amount_sar": 100,
"prob_income": 0.0,
"mean_income": 0.0,
"std_income": 0.0,
"prob_income_sar": 0.0,
"mean_income_sar": 0.0,
"std_income_sar": 0.0,
"mean_outcome": 1000,
"std_outcome": 500,
"mean_outcome_sar": 1000,
"std_outcome_sar": 500,
"mean_phone_change_frequency": 1460,
"std_phone_change_frequency": 365,
"mean_phone_change_frequency_sar": 365,
Expand Down Expand Up @@ -86,7 +96,7 @@
},
"simulator": {
"compute_diameter": false,
"transaction_limit": 10000,
"transaction_limit": 100000,
"transaction_interval": 7,
"sar_interval": 7,
"sar_balance_ratio": 1.0,
Expand Down
10 changes: 10 additions & 0 deletions AMLsim/src/main/java/amlsim/AMLSim.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ private void loadAccountFile(String accountFile) throws IOException {
account = new Account(accountID, normalTxInterval, initBalance, bankID,
getRandom());
}
account.setProp(simProp.getProbIncome(), simProp.getMeanIncome(), simProp.getStdIncome(),
simProp.getProbIncomeSAR(), simProp.getMeanIncomeSAR(), simProp.getStdIncomeSAR(),
simProp.getMeanOutcome(), simProp.getStdOutcome(),
simProp.getMeanOutcomeSar(), simProp.getStdOutcomeSar());

int index = this.getAccounts().size();
account.setBranch(this.branches.get(index % this.numBranches));
Expand Down Expand Up @@ -532,6 +536,11 @@ public void executeSimulation() {
*/
public static void handleTransaction(long step, String desc, double amt, Account orig, Account bene,
boolean isSAR, long alertID, long modelType) {

if (orig.getBalance() < amt || orig.getBalance() <= 0.0) {
return;
}

// Reduce the balance of the originator account
String origID = orig.getID();
String origBankID = orig.getBankID();
Expand All @@ -550,6 +559,7 @@ public static void handleTransaction(long step, String desc, double amt, Account
long benePhoneChanges = (long) bene.getNumberOfPhoneChanges();
long beneDaysInBank = (long) bene.getDaysInBank();


txs.addTransaction(step, desc, amt, origID, origBankID, beneID, beneBankID, origBefore, origAfter, beneBefore,
beneAfter, isSAR, alertID, modelType, origPhoneChanges, benePhoneChanges, origDaysInBank,
beneDaysInBank);
Expand Down
138 changes: 88 additions & 50 deletions AMLsim/src/main/java/amlsim/Account.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import amlsim.model.*;
import amlsim.model.cash.CashInModel;
import amlsim.model.cash.CashOutModel;
import net.bytebuddy.dynamic.scaffold.MethodGraph.Linked;
import sim.engine.SimState;
import sim.engine.Steppable;
import java.util.*;
Expand All @@ -28,23 +29,19 @@ public class Account implements Steppable {
private double monthlyIncome = 0; // Salary
private double monthlyIncomeSar = 0; //
private double monthlyOutcome = 0; // Rent
private double monthlyOutcomeSar = 0; // Rent
private int stepMonthlyOutcome = 26; // Step of monthly outcome
private double probIncome = 0.1; // Probability of income
private double meanIncome = 1000; // Mean income
private double stdIncome = 100; // Standard deviation of income
private double probIncomeSar = 0.05; // Probability of income
private double meanIncomeSar = 1000; // Mean income
private double stdIncomeSar = 100; // Standard deviation of income
private double probOutcome = 0.05; // Probability of outcome
private double meanOutcome = 500; // Mean outcome
private double stdOutcome = 200; // Standard deviation of outcome
private double probOutcomeSar = 0.1; // Probability of outcome
private double meanOutcomeSar = 500; // Mean outcome
private double stdOutcomeSar = 200; // Standard deviation of outcome

private Account prevOrig = null; // Previous originator account
private Account debtor = null; // Previous beneficiary account
private double debt = 0; // Amount of money owed to the previous beneficiary account

private double probIncome; // Probability of income
private double meanIncome; // Mean income
private double stdIncome; // Standard deviation of income
private double probIncomeSar; // Probability of income
private double meanIncomeSar; // Mean income
private double stdIncomeSar; // Standard deviation of income
private double meanOutcome; // Mean outcome
private double stdOutcome; // Standard deviation of outcome
private double meanOutcomeSar; // Mean outcome
private double stdOutcomeSar; // Standard deviation of outcome

List<Alert> alerts = new ArrayList<>();
List<AccountGroup> accountGroups = new ArrayList<>();
Expand All @@ -65,7 +62,7 @@ public class Account implements Steppable {

private AccountBehaviour accountBehaviour;

private double[] balanceHistory = new double[14];
private LinkedList<Double> balanceHistory = new LinkedList<Double>();

public Account() {
this.id = "-";
Expand Down Expand Up @@ -96,16 +93,19 @@ public Account(String id, int interval, float initBalance, String bankID, Random

this.accountBehaviour = new AccountBehaviour(this.isSAR);

//Set monthlyIncome
// Set monthlyIncome
this.monthlyIncome = new SalaryDistribution().sample();
if (random.nextDouble() < 0.5) {
this.monthlyIncomeSar = new SalaryDistribution().sample() * 0.5;
} else {
this.monthlyIncomeSar = new SalaryDistribution().sample() * 1.5;
}
this.monthlyIncomeSar = new SalaryDistribution().sample();

//Set monthlyOutcome
// Set monthlyOutcome
this.monthlyOutcome = new TruncatedNormal(0.5*this.monthlyIncome, 0.1*this.monthlyIncome, 0.1*this.monthlyIncome, 0.9*this.monthlyIncome).sample();
this.monthlyOutcomeSar = new TruncatedNormal(0.5*this.monthlyIncomeSar, 0.1*this.monthlyIncomeSar, 0.1*this.monthlyIncomeSar, 0.9*this.monthlyIncome).sample();

// Set balanceHistory
for (int i = 0; i < 28; i++) {
this.balanceHistory.add((double) initBalance);
}
AMLSim.handleIncome(0, "INITALBALANCE", initBalance, this, false, (long) -1, (long) 11);
}

public String getBankID() {
Expand Down Expand Up @@ -141,11 +141,11 @@ public void setBalance(double balance) {
this.balance = balance;
}

public void withdraw(double ammount) {
if (this.balance < ammount) {
this.balance = 0;
public void withdraw(double amount) {
if (this.balance < amount) {
this.balance = 0.0;
} else {
this.balance -= ammount;
this.balance -= amount;
}
}

Expand Down Expand Up @@ -256,6 +256,19 @@ public void addAccountGroup(AccountGroup accountGroup) {
this.accountGroups.add(accountGroup);
}

public void setProp(double probIncome, double meanIncome, double stdIncome, double probIncomeSar, double meanIncomeSar, double stdIncomeSar, double meanOutcome, double stdOutcome, double meanOutcomeSar, double stdOutcomeSar) {
this.probIncome = probIncome;
this.meanIncome = meanIncome;
this.stdIncome = stdIncome;
this.probIncomeSar = probIncomeSar;
this.meanIncomeSar = meanIncomeSar;
this.stdIncomeSar = stdIncomeSar;
this.meanOutcome = meanOutcome;
this.stdOutcome = stdOutcome;
this.meanOutcomeSar = meanOutcome;
this.stdOutcomeSar = stdOutcome;
}

/**
* Perform transactions
*
Expand All @@ -266,61 +279,86 @@ public void step(SimState state) {
long currentStep = state.schedule.getSteps(); // Current simulation step
long start = this.startStep >= 0 ? this.startStep : 0;
long end = this.endStep > 0 ? this.endStep : AMLSim.getNumOfSteps();

this.balanceHistory.removeFirst();
this.balanceHistory.addLast(this.balance);

if (!this.isSAR) {
// Handle salary, if 25th of the month, deposit salary
if (currentStep % 28 == 25) {
AMLSim.handleIncome(currentStep, "TRANSFER", this.monthlyIncome, this, this.isSAR, (long) -1, (long) 11);
}
// Handle monthly outcome, if 26th to 28th of the month, pay monthly expense
if (currentStep == this.stepMonthlyOutcome) {
AMLSim.handleOutcome(currentStep, "TRANSFER", this.monthlyOutcome, this, this.isSAR, (long) -1, (long) 11);
int currentMonth = (int) (currentStep / 28);
this.stepMonthlyOutcome = 28 * (currentMonth + 1) + random.nextInt(3);
}
// Handle income
if (this.random.nextDouble() < this.probIncome) {
TruncatedNormal tn = new TruncatedNormal(this.meanIncome, this.stdIncome, 0, 1000000);
double amt = tn.sample();
AMLSim.handleIncome(currentStep, "TRANSFER", amt, this, this.isSAR, (long) -1, (long) 0);
}
// Handle monthly outcome, if 26th to 28th of the month, pay monthly expense
if (currentStep == this.stepMonthlyOutcome) {
AMLSim.handleOutcome(currentStep, "TRANSFER", this.monthlyOutcome, this, this.isSAR, (long) -1, (long) 11);
int diff = this.stepMonthlyOutcome % 28 - 25;
diff = diff < 0 ? 3 : diff;
this.stepMonthlyOutcome = this.stepMonthlyOutcome + 28 - diff + random.nextInt(4);
}
// Handle outcome
if (this.random.nextDouble() < this.probOutcome) {
TruncatedNormal tn = new TruncatedNormal(this.meanOutcome, this.stdOutcome, 0, 0.9*this.balance);
double meanBalance = 0.0;
for (double balance : balanceHistory) {
meanBalance += balance / 28;
}
//System.out.println("meanBalance = " + meanBalance + ", balance = " + this.balance + ", inital balance = " + balanceHistory[0]);
double x = (this.balance - meanBalance) / meanBalance;
double sigmoid = 1 / (1 + Math.exp(-x));
if (this.random.nextDouble() < sigmoid) {
TruncatedNormal tn = new TruncatedNormal(this.meanOutcome, this.stdOutcome, 0.0, 0.9*this.balance);
double amt = tn.sample();
AMLSim.handleOutcome(currentStep, "TRANSFER", amt, this, this.isSAR, (long) -1, (long) 0);
if (this.balance > amt) {
AMLSim.handleOutcome(currentStep, "TRANSFER", amt, this, this.isSAR, (long) -1, (long) 0);
}
}
} else {
// Handle salary, if 25th of the month, deposit salary
if (currentStep % 28 == 25) {
AMLSim.handleIncome(currentStep, "TRANSFER", this.monthlyIncomeSar, this, this.isSAR, (long) -1, (long) 11);
}
// Handle monthly outcome, if 26th to 28th of the month, pay monthly expense
if (currentStep == this.stepMonthlyOutcome) {
AMLSim.handleOutcome(currentStep, "TRANSFER", this.monthlyOutcome, this, this.isSAR, (long) -1, (long) 11);
int currentMonth = (int) (currentStep / 28);
this.stepMonthlyOutcome = 28 * (currentMonth + 1) + random.nextInt(3);
}
// Handle income
if (this.random.nextDouble() < this.probIncomeSar) {
TruncatedNormal tn = new TruncatedNormal(this.meanIncomeSar, this.stdIncomeSar, 1.0, 1000000); // TODO: handle lb better, maybe define in conf.json?
double amt = tn.sample();
AMLSim.handleIncome(currentStep, "TRANSFER", amt, this, this.isSAR, (long) -1, (long) 0);
}
// Handle monthly outcome, if 26th to 28th of the month, pay monthly expense
if (currentStep == this.stepMonthlyOutcome) {
AMLSim.handleOutcome(currentStep, "TRANSFER", this.monthlyOutcomeSar, this, this.isSAR, (long) -1, (long) 11);
int diff = (this.stepMonthlyOutcome % 28) - 25;
diff = diff < 0 ? 3 : diff;
int nextStep = this.stepMonthlyOutcome + 28 - diff + random.nextInt(4);
this.stepMonthlyOutcome = nextStep;
}
// Handle outcome
if (this.random.nextDouble() < this.probOutcomeSar) {
double meanBalance = 0.0;
for (double balance : balanceHistory) {
meanBalance += balance / 28;
}
meanBalance = meanBalance <= 100.0 ? 1000.0 : meanBalance;
double x = (this.balance - meanBalance) / meanBalance;
double sigmoid = 1 / (1 + Math.exp(-x));
if (this.random.nextDouble() < sigmoid) {
double probSpendCash = -1.0;
if (cashBalance > 1.0) {
probSpendCash = 0.9;
probSpendCash = 0.9; // TODO: add to conf.json
}
if (this.random.nextDouble() < probSpendCash) {
TruncatedNormal tn = new TruncatedNormal(this.meanOutcomeSar, this.stdOutcomeSar, 1.0, this.cashBalance); // TODO: handle lb better, maybe define in conf.json?
TruncatedNormal tn = new TruncatedNormal(this.meanOutcomeSar, this.stdOutcomeSar, 0.0, this.cashBalance); // TODO: handle lb better, maybe define in conf.json?
double amt = tn.sample();
AMLSim.handleOutcome(currentStep, "CASH", amt, this, this.isSAR, (long) -1, (long) 0);
if (this.cashBalance > amt) {
AMLSim.handleOutcome(currentStep, "CASH", amt, this, this.isSAR, (long) -1, (long) 0);
}
} else {
TruncatedNormal tn = new TruncatedNormal(this.meanOutcomeSar, this.stdOutcomeSar, 1.0, 0.9*this.balance); // TODO: handle lb better, maybe define in conf.json?
TruncatedNormal tn = new TruncatedNormal(this.meanOutcomeSar, this.stdOutcomeSar, 0.0, 0.9*this.balance); // TODO: handle lb better, maybe define in conf.json?
double amt = tn.sample();
AMLSim.handleOutcome(currentStep, "TRANSFER", amt, this, this.isSAR, (long) -1, (long) 0);
if (this.balance > amt) {
AMLSim.handleOutcome(currentStep, "TRANSFER", amt, this, this.isSAR, (long) -1, (long) 0);
}
}
}
}
Expand Down
54 changes: 30 additions & 24 deletions AMLsim/src/main/java/amlsim/SimProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,11 @@ public class SimProperties {
private double probIncomeSAR;
private double meanIncomeSAR;
private double stdIncomeSAR;
//private double probOutcome;
//private double meanOutcome;
//private double stdOutcome;
//private double probOutcomeSar;
//private double meanOutcomeSar;
//private double stdOutcomeSar;

private double meanOutcome;
private double stdOutcome;
private double meanOutcomeSar;
private double stdOutcomeSar;

SimProperties(String jsonName) throws IOException {
String jsonStr = loadTextFile(jsonName);
JSONObject jsonObject = new JSONObject(jsonStr);
Expand Down Expand Up @@ -85,12 +83,16 @@ public class SimProperties {
meanBankChangeFrequencySAR = defaultProp.getDouble("mean_bank_change_frequency_sar");
stdBankChangeFrequencySAR = defaultProp.getDouble("std_bank_change_frequency_sar");

//probIncome = defaultProp.getDouble("prob_income");
//meanIncome = defaultProp.getDouble("mean_income");
//stdIncome = defaultProp.getDouble("std_income");
//probIncome = defaultProp.getDouble("prob_income_sar");
//meanIncome = defaultProp.getDouble("mean_income_sar");
//stdIncome = defaultProp.getDouble("std_income_sar");
probIncome = defaultProp.getDouble("prob_income");
meanIncome = defaultProp.getDouble("mean_income");
stdIncome = defaultProp.getDouble("std_income");
probIncome = defaultProp.getDouble("prob_income_sar");
meanIncome = defaultProp.getDouble("mean_income_sar");
stdIncome = defaultProp.getDouble("std_income_sar");
meanOutcome = defaultProp.getDouble("mean_outcome");
stdOutcome = defaultProp.getDouble("std_outcome");
meanOutcomeSar = defaultProp.getDouble("mean_outcome_sar");
stdOutcomeSar = defaultProp.getDouble("std_outcome_sar");

System.out.printf("General transaction interval: %d\n", normalTxInterval);
System.out.printf("Base transaction amount: Normal = %f, Suspicious= %f\n", minTxAmount, maxTxAmount);
Expand Down Expand Up @@ -224,18 +226,22 @@ public double getStdIncomeSAR() {
return stdIncomeSAR;
}

//public double getProbOutcome() {
// return probOutcome;
//}
//
//public double getMeanOutcome() {
// return meanOutcome;
//}
//
//public double getStdOutcome() {
// return stdOutcome;
//}
public double getMeanOutcome() {
return meanOutcome;
}

public double getStdOutcome() {
return stdOutcome;
}

public double getMeanOutcomeSar() {
return meanOutcomeSar;
}

public double getStdOutcomeSar() {
return stdOutcomeSar;
}

public double getMarginRatio() {
return marginRatio;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ protected void makeTransaction(long step, double amount, Account orig, Account d
if (isSAR) {
AMLSim.getLogger().fine("Handle transaction: " + orig.getID() + " -> " + dest.getID());
}
if (amount > orig.getBalance()) {
//System.out.println("Invalid transaction amount: " + amount + " > " + orig.getBalance());
}
if (orig.getBalance() <= 100.0) {
//System.out.println("Error! Balance: " + orig.getBalance() + ", amount: " + amount);
}
AMLSim.handleTransaction(step, ttype, amount, orig, dest, isSAR, alertID, modelType);
}

Expand Down
2 changes: 1 addition & 1 deletion AMLsim/src/main/java/amlsim/model/aml/StackTypology.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public void sendTransactions(long step, Account acct) {
// makeTransaction(step, transactionAmount.doubleValue(), orig, bene, AMLTypology.STACK);
// }
//}
if (step == this.stepReciveFunds) {
if (step == this.stepReciveFunds) {
int numOrigs = origIdxs.length;
for (int i = 0; i < numOrigs; i++) {
Account orig = members.get(origIdxs[i]);
Expand Down
Binary file modified AMLsim/target/amlsim-1.0.0.jar
Binary file not shown.
Binary file modified AMLsim/target/classes/amlsim/SimProperties.class
Binary file not shown.
Binary file modified AMLsim/target/classes/amlsim/TargetedTransactionAmount.class
Binary file not shown.
2 changes: 1 addition & 1 deletion AMLsim/target/maven-archiver/pom.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#Generated by Maven
#Tue Nov 07 15:13:54 UTC 2023
#Thu Nov 09 09:36:01 UTC 2023
groupId=amlsim
artifactId=amlsim
version=1.0.0

0 comments on commit 837c6bb

Please sign in to comment.