Skip to content

Commit

Permalink
made sure of no neg balance
Browse files Browse the repository at this point in the history
  • Loading branch information
TheColdIce committed Nov 10, 2023
1 parent 09732f8 commit 9978d63
Show file tree
Hide file tree
Showing 28 changed files with 181 additions and 453 deletions.
4 changes: 2 additions & 2 deletions AMLsim/paramFiles/10K_accts/conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"min_amount": 1,
"max_amount": 150000,
"mean_amount": 637,
"std_amount": 100,
"std_amount": 300,
"mean_amount_sar": 1000,
"std_amount_sar": 100,
"std_amount_sar": 300,
"prob_income": 0.0,
"mean_income": 0.0,
"std_income": 0.0,
Expand Down
12 changes: 6 additions & 6 deletions AMLsim/paramFiles/10K_accts/normalModels.csv
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
count,type,schedule_id,min_accounts,max_accounts,min_period,max_period,bank_id
4000,single,2,1,1,1,365,
4000,fan_out,2,4,4,1,365,
4000,fan_in,2,4,4,1,365,
4000,forward,2,3,3,1,365,
4000,mutual,2,2,2,1,365,
4000,periodical,2,2,2,1,365,
5000,single,2,1,1,1,365,
5000,fan_out,2,4,4,1,365,
5000,fan_in,2,4,4,1,365,
5000,forward,2,3,3,1,365,
5000,mutual,2,2,2,1,365,
5000,periodical,2,2,2,1,365,
12 changes: 11 additions & 1 deletion AMLsim/paramFiles/20K_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
63 changes: 28 additions & 35 deletions AMLsim/src/main/java/amlsim/AMLSim.java
Original file line number Diff line number Diff line change
Expand Up @@ -537,34 +537,33 @@ 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) {
// //System.out.println("error! balance = " + orig.getBalance() + ", amount = " + amt);
// return;
//}
if (orig.getBalance() < amt || orig.getBalance() <= 0.0) {
return;
}

// Reduce the balance of the originator account
String origID = orig.getID();
String origBankID = orig.getBankID();
float origBefore = (float) orig.getBalance();
orig.withdraw(amt);
boolean success = orig.withdraw(amt);
float origAfter = (float) orig.getBalance();
long origPhoneChanges = (long) orig.getNumberOfPhoneChanges();
long origDaysInBank = (long) orig.getDaysInBank();

// Increase the balance of the beneficiary account
String beneID = bene.getID();
String beneBankID = bene.getBankID();
float beneBefore = (float) bene.getBalance();
bene.deposit(amt);
float beneAfter = (float) bene.getBalance();
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);
diameter.addEdge(origID, beneID);
if (success) {
// Increase the balance of the beneficiary account
String beneID = bene.getID();
String beneBankID = bene.getBankID();
float beneBefore = (float) bene.getBalance();
bene.deposit(amt);
float beneAfter = (float) bene.getBalance();
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);
diameter.addEdge(origID, beneID);
}
}

public static void handleIncome(long step, String desc, double amt, Account bene, boolean isSAR, long alertID, long modelType) {
Expand All @@ -583,33 +582,27 @@ public static void handleIncome(long step, String desc, double amt, Account bene

public static void handleOutcome(long step, String desc, double amt, Account orig, boolean isSAR, long alertID, long modelType) {

//boolean e;
//if (orig.getBalance() < amt || orig.getBalance() <= 0.0) {
// //System.out.println("outcome error! balance = " + orig.getBalance() + ", amount = " + amt);
// e = true;
// return;
//} else {
// e = false;
//}
//if (e) {
// System.out.println("wtf");
//}

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

// Reduce the balance of the originator account
String origID = orig.getID();
String origBankID = orig.getBankID();
float origBefore = (float) orig.getBalance();
boolean success = false;
if (desc.equals("CASH")) {
orig.withdrawCash(amt);
success = orig.withdrawCash(amt);
} else {
orig.withdraw(amt);
success = orig.withdraw(amt);
}
float origAfter = (float) orig.getBalance();
long origPhoneChanges = (long) orig.getNumberOfPhoneChanges();
long origDaysInBank = (long) orig.getDaysInBank();

txs.addTransaction(step, desc, amt, origID, origBankID, "-1", "sink", origBefore, origAfter, 0, 0, isSAR, alertID, modelType,
if (success) {
txs.addTransaction(step, desc, amt, origID, origBankID, "-1", "sink", origBefore, origAfter, 0, 0, isSAR, alertID, modelType,
origPhoneChanges, 0, origDaysInBank, 0);
}
}

/**
Expand Down
72 changes: 39 additions & 33 deletions AMLsim/src/main/java/amlsim/Account.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,25 +148,33 @@ public boolean withdraw(double amount) {
// this.balance -= amount;
//}
boolean success;
if (this.balance > amount) {
if (this.balance > amount && amount > 0.0 && this.balance >= 100.0) {
this.balance -= amount;
success = true;
} else {
success = false;
}
return success
return success;
}

public void deposit(double ammount) {
this.balance += ammount;
public void deposit(double amount) {
this.balance += amount;
}

public void withdrawCash(double ammount){
if (this.cashBalance < ammount) {
this.cashBalance = 0;
public boolean withdrawCash(double amount){
//if (this.cashBalance < ammount) {
// this.cashBalance = 0;
//} else {
// this.cashBalance -= ammount;
//}
boolean success;
if (this.cashBalance > amount && amount > 0.0 && this.cashBalance >= 100.0) {
this.balance -= amount;
success = true;
} else {
this.cashBalance -= ammount;
success = false;
}
return success;
}

public void depositCash(double ammount){
Expand Down Expand Up @@ -289,7 +297,7 @@ public void step(SimState state) {
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) {
Expand All @@ -301,28 +309,26 @@ public void step(SimState state) {
double amt = tn.sample();
AMLSim.handleIncome(currentStep, "TRANSFER", amt, this, this.isSAR, (long) -1, (long) 0);
}
if (this.balance >= 100.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
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();
if (this.balance > amt) {
AMLSim.handleOutcome(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
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();
if (this.balance > amt && amt > 0.0 && this.balance >= 100.0) {
AMLSim.handleOutcome(currentStep, "TRANSFER", amt, this, this.isSAR, (long) -1, (long) 0);
}
}
} else {
Expand Down Expand Up @@ -360,13 +366,13 @@ public void step(SimState state) {
if (this.random.nextDouble() < probSpendCash) {
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();
if (this.cashBalance > amt) {
if (this.cashBalance > amt && amt > 0.0) {
AMLSim.handleOutcome(currentStep, "CASH", amt, this, this.isSAR, (long) -1, (long) 0);
}
} else {
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();
if (this.balance > amt) {
if (this.balance > amt && amt > 0.0 && this.balance >= 100.0) {
AMLSim.handleOutcome(currentStep, "TRANSFER", amt, this, this.isSAR, (long) -1, (long) 0);
}
}
Expand Down
13 changes: 0 additions & 13 deletions AMLsim/src/main/java/amlsim/AccountGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,6 @@ public class AccountGroup {
assert startStep < endStep : "startStep must be smaller than endStep";
assert interval > 0 : "interval must be positive";

//if (startStep >= 0 && startStep < AMLSim.getNumOfSteps()) {
// int range = (int) (endStep - startStep + 1);
// this.startStep = AMLSim.getRandom().nextInt(range) + startStep;
//} else {
// this.startStep = AMLSim.getRandom().nextInt((int) AMLSim.getNumOfSteps() - 1);
//}
//
//if (endStep >= 0 && endStep < AMLSim.getNumOfSteps()) {
// this.endStep = endStep;
//} else {
// this.endStep = AMLSim.getNumOfSteps();
//}

long s1 = startStep + AMLSim.getRandom().nextInt((int) (endStep - startStep + 1));
long s2 = startStep + AMLSim.getRandom().nextInt((int) (endStep - startStep + 1));
this.startStep = Math.min(s1, s2);
Expand Down
6 changes: 6 additions & 0 deletions AMLsim/src/main/java/amlsim/TransactionRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ void addTransaction(long step, String desc, double amt, String origID, String or
String destBankID, float origBefore, float origAfter, float destBefore, float destAfter, boolean isSAR,
long aid, long modelType, long origPhoneChange, long destPhoneChange, long origDaysInBank,
long destDaysInBank) {

if (origID != "-2" && amt > origBefore) {
System.err.println("Warning: the amount of transaction is larger than the balance: " + amt + " > "
+ origBefore + " (" + origID + " -> " + destID + ")");
}

if (count >= limit) {
if (count == limit) {
System.err.println("Warning: the number of output transactions has reached the limit: " + limit);
Expand Down
12 changes: 2 additions & 10 deletions AMLsim/src/main/java/amlsim/model/AbstractTransactionModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,6 @@ public void setParameters(long start, long end) {
*/
protected void makeTransaction(long step, double amount, Account orig, Account dest, boolean isSAR, long alertID,
long modelType) {
if (amount <= 0) { // Invalid transaction amount
// AMLSim.getLogger().warning("Warning: invalid transaction amount: " + amount);
return;
}
if (orig.getBalance() < 100) { // Insufficient balance
// AMLSim.getLogger().warning("Warning: insufficient balance: " + orig.getBalance());
return;
Expand All @@ -157,13 +153,9 @@ 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);
if (orig.getBalance() > amount && amount > 0.0 && orig.getBalance() >= 100.0) {
AMLSim.handleTransaction(step, ttype, amount, orig, dest, isSAR, alertID, modelType);
}
AMLSim.handleTransaction(step, ttype, amount, orig, dest, isSAR, alertID, modelType);
}

/**
Expand Down
Binary file modified AMLsim/target/amlsim-1.0.0.jar
Binary file not shown.
Binary file modified AMLsim/target/classes/amlsim/model/aml/BipartiteTypology.class
Binary file not shown.
Binary file modified AMLsim/target/classes/amlsim/model/aml/CycleTypology.class
Binary file not shown.
Binary file modified AMLsim/target/classes/amlsim/model/aml/FanInTypology.class
Binary file not shown.
Binary file modified AMLsim/target/classes/amlsim/model/aml/FanOutTypology.class
Binary file not shown.
Binary file not shown.
Binary file modified AMLsim/target/classes/amlsim/model/aml/RandomTypology.class
Binary file not shown.
Binary file not shown.
Binary file modified AMLsim/target/classes/amlsim/model/aml/StackTypology.class
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
#Fri Nov 10 12:06:32 UTC 2023
#Fri Nov 10 13:32:39 UTC 2023
groupId=amlsim
artifactId=amlsim
version=1.0.0
15 changes: 13 additions & 2 deletions transaction-network-explorer/TransactionNetwork.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ def update_graph(self, banks, laundering_models, legitimate_models, steps, x_ran
def get_balances(self, index):
names = self.df_nodes.loc[index, 'name'].tolist()
# TODO: filter on steps aswell?

'''
df1 = self.df[self.df['nameOrig'].isin(names)][['nameOrig', 'step', 'amount']]
df1 = df1.rename(columns={'nameOrig': 'name'})
df2 = self.df[self.df['nameDest'].isin(names)][['nameDest', 'step', 'amount']]
Expand All @@ -199,16 +201,25 @@ def get_balances(self, index):
df = pd.concat([df1, df2]).reset_index(drop=True)
df = df.sort_values(by=['step'])
df['balance'] = df.groupby('name')['amount'].cumsum()
'''

df1 = self.df[self.df['nameOrig'].isin(names)][['nameOrig', 'step', 'newbalanceOrig']]
df1 = df1.rename(columns={'nameOrig': 'name', 'newbalanceOrig': 'balance'})
df2 = self.df[self.df['nameDest'].isin(names)][['nameDest', 'step', 'newbalanceDest']]
df2 = df2.rename(columns={'nameDest': 'name', 'balance': 'newbalanceDest'})
df = pd.concat([df1, df2]).reset_index(drop=True)
#df = df.sort_values(by=['step']).reset_index(drop=True)

curves = {}
for i, name in enumerate(names):
curves[i] = hv.Curve(df[df['name']==name][['step', 'balance']], 'step', 'balance')
if curves:
curves = hv.NdOverlay(curves).opts(
hv.opts.Curve(xlim=(0, 365), ylim=(0, 100000), interpolation='steps-post', xlabel='step', ylabel='balance')
hv.opts.Curve(xlim=(0, 365), ylim=(0, 100000), xlabel='step', ylabel='balance')#, interpolation='steps-post')
)
else:
curves = hv.NdOverlay({0: hv.Curve(data=sorted(zip([0], [0])))}).opts(
hv.opts.Curve(xlim=(0, 365), ylim=(0, 100000), interpolation='steps-post', xlabel='step', ylabel='balance')
hv.opts.Curve(xlim=(0, 365), ylim=(0, 100000), xlabel='step', ylabel='balance')#, interpolation='steps-post')
)
return curves.opts(shared_axes=False, show_legend=False)

Expand Down
Binary file not shown.
Loading

0 comments on commit 9978d63

Please sign in to comment.