@intentsolutionsio/flash-loan-simulator 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,315 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Flash loan profitability calculator.
4
+
5
+ Calculates net profit after all costs including:
6
+ - Flash loan fees
7
+ - Gas costs
8
+ - DEX fees (implicit in swaps)
9
+ - Slippage
10
+ """
11
+
12
+ from dataclasses import dataclass
13
+ from decimal import Decimal
14
+ from typing import List, Optional
15
+
16
+ from strategy_engine import StrategyResult, TransactionStep
17
+
18
+
19
+ @dataclass
20
+ class ProfitBreakdown:
21
+ """Detailed profit breakdown."""
22
+
23
+ gross_revenue: Decimal
24
+ flash_loan_fee: Decimal
25
+ gas_cost_eth: Decimal
26
+ gas_cost_usd: Decimal
27
+ dex_fees: Decimal
28
+ slippage_cost: Decimal
29
+ total_costs: Decimal
30
+ net_profit: Decimal
31
+ net_profit_usd: Decimal
32
+ roi_percent: float
33
+ breakeven_gas_price: float # Max gas price for profitability
34
+ is_profitable: bool
35
+
36
+
37
+ @dataclass
38
+ class GasEstimate:
39
+ """Gas estimation for a transaction."""
40
+
41
+ gas_units: int
42
+ gas_price_gwei: float
43
+ cost_eth: Decimal
44
+ cost_usd: Decimal
45
+
46
+
47
+ class ProfitCalculator:
48
+ """
49
+ Calculates detailed profitability for flash loan strategies.
50
+
51
+ Accounts for all costs and provides breakeven analysis.
52
+ """
53
+
54
+ def __init__(
55
+ self,
56
+ eth_price_usd: float = 2500.0,
57
+ gas_price_gwei: float = 30.0,
58
+ ):
59
+ """
60
+ Initialize calculator.
61
+
62
+ Args:
63
+ eth_price_usd: Current ETH price
64
+ gas_price_gwei: Current gas price
65
+ """
66
+ self.eth_price_usd = Decimal(str(eth_price_usd))
67
+ self.gas_price_gwei = gas_price_gwei
68
+
69
+ def calculate_breakdown(
70
+ self,
71
+ result: StrategyResult,
72
+ slippage_pct: float = 0.5,
73
+ ) -> ProfitBreakdown:
74
+ """
75
+ Calculate detailed profit breakdown from strategy result.
76
+
77
+ Args:
78
+ result: Strategy simulation result
79
+ slippage_pct: Expected slippage percentage
80
+
81
+ Returns:
82
+ Detailed profit breakdown
83
+ """
84
+ # Calculate gross revenue (profit before any costs)
85
+ gross_revenue = result.gross_profit + result.loan_fee + result.gas_cost_eth
86
+
87
+ # Flash loan fee
88
+ flash_loan_fee = result.loan_fee
89
+
90
+ # Gas costs
91
+ gas_cost_eth = result.gas_cost_eth
92
+ gas_cost_usd = result.gas_cost_usd
93
+
94
+ # DEX fees (usually included in price, but track separately)
95
+ # Estimate ~0.3% per swap
96
+ num_swaps = sum(1 for s in result.steps if s.action == "swap")
97
+ dex_fee_rate = Decimal("0.003") # 0.3%
98
+ dex_fees = result.loan_amount * dex_fee_rate * num_swaps
99
+
100
+ # Slippage cost
101
+ slippage_rate = Decimal(str(slippage_pct / 100))
102
+ slippage_cost = result.loan_amount * slippage_rate
103
+
104
+ # Total costs
105
+ total_costs = flash_loan_fee + gas_cost_eth + slippage_cost
106
+ # Note: DEX fees already reflected in swap outputs
107
+
108
+ # Net profit
109
+ net_profit = result.net_profit
110
+ net_profit_usd = result.net_profit_usd
111
+
112
+ # ROI
113
+ roi = result.roi_percent
114
+
115
+ # Breakeven gas price
116
+ # At what gas price does profit = 0?
117
+ profit_before_gas = gross_revenue - flash_loan_fee - slippage_cost
118
+ total_gas_units = sum(s.gas_estimate for s in result.steps)
119
+
120
+ if total_gas_units > 0 and profit_before_gas > 0:
121
+ # profit_before_gas = gas_units * gas_price * eth_price
122
+ # gas_price = profit_before_gas / (gas_units * eth_price)
123
+ breakeven_gas = float(
124
+ profit_before_gas * Decimal("1e9") / (total_gas_units * self.eth_price_usd)
125
+ )
126
+ else:
127
+ breakeven_gas = 0.0
128
+
129
+ return ProfitBreakdown(
130
+ gross_revenue=gross_revenue,
131
+ flash_loan_fee=flash_loan_fee,
132
+ gas_cost_eth=gas_cost_eth,
133
+ gas_cost_usd=gas_cost_usd,
134
+ dex_fees=dex_fees,
135
+ slippage_cost=slippage_cost,
136
+ total_costs=total_costs,
137
+ net_profit=net_profit,
138
+ net_profit_usd=net_profit_usd,
139
+ roi_percent=roi,
140
+ breakeven_gas_price=breakeven_gas,
141
+ is_profitable=net_profit > 0,
142
+ )
143
+
144
+ def estimate_gas(self, steps: List[TransactionStep]) -> GasEstimate:
145
+ """
146
+ Estimate total gas cost for transaction steps.
147
+
148
+ Args:
149
+ steps: List of transaction steps
150
+
151
+ Returns:
152
+ Gas estimate with cost
153
+ """
154
+ total_units = sum(s.gas_estimate for s in steps)
155
+
156
+ cost_eth = Decimal(total_units * self.gas_price_gwei) / Decimal("1e9")
157
+ cost_usd = cost_eth * self.eth_price_usd
158
+
159
+ return GasEstimate(
160
+ gas_units=total_units,
161
+ gas_price_gwei=self.gas_price_gwei,
162
+ cost_eth=cost_eth,
163
+ cost_usd=cost_usd,
164
+ )
165
+
166
+ def calculate_minimum_profit(
167
+ self,
168
+ loan_amount: Decimal,
169
+ loan_fee_rate: Decimal,
170
+ gas_units: int,
171
+ num_swaps: int = 2,
172
+ ) -> Decimal:
173
+ """
174
+ Calculate minimum profit needed to break even.
175
+
176
+ Useful for determining if an opportunity is worth pursuing.
177
+ """
178
+ # Flash loan fee
179
+ loan_fee = loan_amount * loan_fee_rate
180
+
181
+ # Gas cost
182
+ gas_cost = Decimal(gas_units * self.gas_price_gwei) / Decimal("1e9")
183
+
184
+ # Minimum slippage assumption (0.5%)
185
+ slippage = loan_amount * Decimal("0.005")
186
+
187
+ return loan_fee + gas_cost + slippage
188
+
189
+ def compare_providers(
190
+ self,
191
+ loan_amount: Decimal,
192
+ asset: str,
193
+ gas_units: int,
194
+ providers: dict,
195
+ ) -> List[dict]:
196
+ """
197
+ Compare profitability across flash loan providers.
198
+
199
+ Args:
200
+ loan_amount: Amount to borrow
201
+ asset: Asset to borrow
202
+ gas_units: Base gas units (before provider overhead)
203
+ providers: Dict of provider name -> fee rate
204
+
205
+ Returns:
206
+ List of provider comparisons sorted by net cost
207
+ """
208
+ results = []
209
+
210
+ for name, fee_rate in providers.items():
211
+ # Calculate fee
212
+ fee = loan_amount * Decimal(str(fee_rate))
213
+
214
+ # Estimate gas (with provider overhead)
215
+ overhead = {
216
+ "aave": 100000,
217
+ "dydx": 150000,
218
+ "balancer": 80000,
219
+ }.get(name.lower(), 100000)
220
+
221
+ total_gas = gas_units + overhead
222
+ gas_cost = Decimal(total_gas * self.gas_price_gwei) / Decimal("1e9")
223
+
224
+ total_cost = fee + gas_cost
225
+
226
+ results.append({
227
+ "provider": name,
228
+ "fee_rate": float(fee_rate) * 100,
229
+ "fee_amount": float(fee),
230
+ "gas_overhead": overhead,
231
+ "gas_cost_eth": float(gas_cost),
232
+ "total_cost_eth": float(total_cost),
233
+ "total_cost_usd": float(total_cost * self.eth_price_usd),
234
+ })
235
+
236
+ # Sort by total cost
237
+ results.sort(key=lambda x: x["total_cost_eth"])
238
+
239
+ return results
240
+
241
+
242
+ def demo():
243
+ """Demonstrate profit calculator."""
244
+ from strategy_engine import StrategyFactory, StrategyType, ArbitrageParams
245
+
246
+ # Run a simulation first
247
+ factory = StrategyFactory()
248
+ strategy = factory.create(StrategyType.SIMPLE_ARBITRAGE)
249
+
250
+ params = ArbitrageParams(
251
+ input_token="ETH",
252
+ output_token="USDC",
253
+ amount=Decimal("100"),
254
+ dex_buy="sushiswap",
255
+ dex_sell="uniswap",
256
+ provider="aave",
257
+ )
258
+
259
+ result = strategy.simulate(params)
260
+
261
+ # Calculate detailed breakdown
262
+ calculator = ProfitCalculator(eth_price_usd=2500.0, gas_price_gwei=30.0)
263
+ breakdown = calculator.calculate_breakdown(result)
264
+
265
+ print("=" * 60)
266
+ print("PROFIT BREAKDOWN")
267
+ print("=" * 60)
268
+
269
+ print(f"\nGross Revenue: {breakdown.gross_revenue:.6f} ETH")
270
+ print(f"\nCosts:")
271
+ print(f" Flash Loan Fee: -{breakdown.flash_loan_fee:.6f} ETH")
272
+ print(f" Gas Cost: -{breakdown.gas_cost_eth:.6f} ETH (${breakdown.gas_cost_usd:.2f})")
273
+ print(f" Est. Slippage: -{breakdown.slippage_cost:.6f} ETH")
274
+ print(f" ────────────────────────────────")
275
+ print(f" Total Costs: -{breakdown.total_costs:.6f} ETH")
276
+
277
+ print(f"\nNet Profit: {breakdown.net_profit:.6f} ETH (${breakdown.net_profit_usd:.2f})")
278
+ print(f"ROI: {breakdown.roi_percent:.4f}%")
279
+ print(f"Breakeven Gas: {breakdown.breakeven_gas_price:.1f} gwei")
280
+ print(f"\nProfitable: {'YES ✓' if breakdown.is_profitable else 'NO ✗'}")
281
+
282
+ # Compare providers
283
+ print("\n" + "=" * 60)
284
+ print("PROVIDER COMPARISON")
285
+ print("=" * 60)
286
+
287
+ providers = {
288
+ "Aave V3": 0.0009,
289
+ "dYdX": 0.0,
290
+ "Balancer": 0.0001,
291
+ }
292
+
293
+ comparisons = calculator.compare_providers(
294
+ loan_amount=Decimal("100"),
295
+ asset="ETH",
296
+ gas_units=300000,
297
+ providers=providers,
298
+ )
299
+
300
+ print(f"\nFor 100 ETH flash loan:")
301
+ print(f"{'Provider':<12} {'Fee %':<8} {'Fee ETH':<12} {'Gas ETH':<12} {'Total':<12}")
302
+ print("-" * 56)
303
+
304
+ for comp in comparisons:
305
+ print(
306
+ f"{comp['provider']:<12} "
307
+ f"{comp['fee_rate']:.2f}%{'':<4} "
308
+ f"{comp['fee_amount']:.4f}{'':<6} "
309
+ f"{comp['gas_cost_eth']:.4f}{'':<6} "
310
+ f"{comp['total_cost_eth']:.4f}"
311
+ )
312
+
313
+
314
+ if __name__ == "__main__":
315
+ demo()