yeref 0.24.89__tar.gz → 0.24.91__tar.gz
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.
- {yeref-0.24.89 → yeref-0.24.91}/PKG-INFO +1 -1
- {yeref-0.24.89 → yeref-0.24.91}/setup.py +1 -1
- {yeref-0.24.89 → yeref-0.24.91}/yeref/yeref.py +95 -302
- {yeref-0.24.89 → yeref-0.24.91}/yeref.egg-info/PKG-INFO +1 -1
- {yeref-0.24.89 → yeref-0.24.91}/pyproject.toml +0 -0
- {yeref-0.24.89 → yeref-0.24.91}/setup.cfg +0 -0
- {yeref-0.24.89 → yeref-0.24.91}/yeref/__init__.py +0 -0
- {yeref-0.24.89 → yeref-0.24.91}/yeref/l_.py +0 -0
- {yeref-0.24.89 → yeref-0.24.91}/yeref/tonweb.js +0 -0
- {yeref-0.24.89 → yeref-0.24.91}/yeref.egg-info/SOURCES.txt +0 -0
- {yeref-0.24.89 → yeref-0.24.91}/yeref.egg-info/dependency_links.txt +0 -0
- {yeref-0.24.89 → yeref-0.24.91}/yeref.egg-info/top_level.txt +0 -0
@@ -15926,7 +15926,7 @@ async def upd_user_data(ENT_TID, data, web_app_init_data, PROJECT_USERNAME, BASE
|
|
15926
15926
|
|
15927
15927
|
|
15928
15928
|
# region unit ecomonics
|
15929
|
-
async def
|
15929
|
+
async def calc_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
15930
15930
|
try:
|
15931
15931
|
schema_name = "USER"
|
15932
15932
|
if PROJECT_USERNAME == 'FereyBotBot':
|
@@ -15939,6 +15939,84 @@ async def return_activity_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
15939
15939
|
sql = f"SELECT {schema_name}_TID FROM \"{schema_name}\""
|
15940
15940
|
data_ents = await db_select_pg(sql, (), BASE_P)
|
15941
15941
|
|
15942
|
+
sql = 'SELECT USER_TID, USER_VARS, USER_LSTS FROM "USER"'
|
15943
|
+
data_users = await db_select_pg(sql, (), BASE_P)
|
15944
|
+
|
15945
|
+
months = ["2025-06", "2025-07", "2025-08", "2025-09"]
|
15946
|
+
data_users = []
|
15947
|
+
for _ in range(30):
|
15948
|
+
# дата входа
|
15949
|
+
entry_month = random.choice(months)
|
15950
|
+
entry_day = random.randint(1, 28)
|
15951
|
+
entry_date = f"{entry_month}-{entry_day:02}"
|
15952
|
+
entry_dt_obj = datetime.strptime(entry_date, '%Y-%m-%d')
|
15953
|
+
entry_dt = f"{entry_dt_obj.strftime('%d-%m-%Y')}_{datetime.now().strftime('%H-%M-%S')}"
|
15954
|
+
utm = random.choice(["/start", "/startapp"])
|
15955
|
+
|
15956
|
+
# месяцы от входа и дальше
|
15957
|
+
valid_months = [m for m in months if datetime.strptime(m + "-01", "%Y-%m-%d") >= entry_dt_obj.replace(day=1)]
|
15958
|
+
if not valid_months:
|
15959
|
+
valid_months = [entry_month]
|
15960
|
+
|
15961
|
+
user_mau = sorted(random.sample(valid_months, k=random.randint(1, len(valid_months))))
|
15962
|
+
user_dau_dates = set()
|
15963
|
+
txs, payments = [], []
|
15964
|
+
|
15965
|
+
# платеж
|
15966
|
+
if user_mau:
|
15967
|
+
pay_month = random.choice(user_mau)
|
15968
|
+
pay_day = random.randint(1, 28)
|
15969
|
+
pay_date = f"{pay_month}-{pay_day:02}"
|
15970
|
+
dt_pay = datetime.strptime(pay_date, "%Y-%m-%d")
|
15971
|
+
payments = [{
|
15972
|
+
"TYPE": random.choice(["don", "sub", "pst"]),
|
15973
|
+
"DT_START": f"{dt_pay.strftime('%d-%m-%Y')}_14-00-00",
|
15974
|
+
"DT_END": "0",
|
15975
|
+
"AMOUNT": str(random.randint(10, 1000))
|
15976
|
+
}]
|
15977
|
+
user_dau_dates.add(pay_date)
|
15978
|
+
|
15979
|
+
# вход в приложение
|
15980
|
+
user_dau_dates.add(entry_date)
|
15981
|
+
for m in user_mau:
|
15982
|
+
day = random.randint(1, 28)
|
15983
|
+
visit = f"{m}-{day:02}"
|
15984
|
+
dt_visit = datetime.strptime(visit, "%Y-%m-%d")
|
15985
|
+
if dt_visit >= entry_dt_obj and random.random() < 0.7:
|
15986
|
+
user_dau_dates.add(visit)
|
15987
|
+
|
15988
|
+
# статусы (отток) с низкой вероятностью
|
15989
|
+
USER_STATUSES = []
|
15990
|
+
if random.random() < 0.2: # 10% шанс оттока
|
15991
|
+
churn_month = random.choice(valid_months)
|
15992
|
+
churn_day = random.randint(1, 28)
|
15993
|
+
churn_date = f"{churn_month}-{churn_day:02}"
|
15994
|
+
churn_ts = datetime.strptime(churn_date, "%Y-%m-%d").strftime("%d-%m-%Y") + "_23-59-59"
|
15995
|
+
USER_STATUSES = [{random.choice(["left", "kicked"]): churn_ts}]
|
15996
|
+
|
15997
|
+
user_dau = sorted(user_dau_dates)
|
15998
|
+
wallet = f"wallet{random.randint(1, 100)}" if txs else random.choice([f"wallet{random.randint(1, 100)}", ""])
|
15999
|
+
|
16000
|
+
data_users.append((
|
16001
|
+
random.randint(100000, 999999),
|
16002
|
+
json.dumps({"USER_WALLET": wallet, "USER_UTM": utm, "USER_DT": entry_dt}),
|
16003
|
+
json.dumps({"USER_DAU": user_dau, "USER_MAU": user_mau, "USER_TXS": txs,
|
16004
|
+
"USER_PAYMENTS": payments, "USER_STATUSES": USER_STATUSES})
|
16005
|
+
))
|
16006
|
+
print(f"gen {data_users=}")
|
16007
|
+
|
16008
|
+
await return_activity_metrics(bot, data_users, EXTRA_D, BASE_P, data_ents, schema_name)
|
16009
|
+
await return_unit_metrics(bot, data_users, EXTRA_D, BASE_P)
|
16010
|
+
await return_cohort_metrics(bot, data_users, EXTRA_D, BASE_P)
|
16011
|
+
await return_retention_metrics(bot, data_users, EXTRA_D, BASE_P)
|
16012
|
+
await return_profit_and_loss_metrics(bot, data_users, EXTRA_D, BASE_P)
|
16013
|
+
except Exception as e:
|
16014
|
+
logger.info(log_ % str(e))
|
16015
|
+
await asyncio.sleep(round(random.uniform(0, 1), 2))
|
16016
|
+
|
16017
|
+
|
16018
|
+
async def return_activity_metrics(bot, data_users, EXTRA_D, BASE_P, data_ents, schema_name):
|
16019
|
+
try:
|
15942
16020
|
metrics_by_month = defaultdict(lambda: {
|
15943
16021
|
"dau": 0,
|
15944
16022
|
"mau": 0,
|
@@ -15953,79 +16031,8 @@ async def return_activity_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
15953
16031
|
seen_dau = set()
|
15954
16032
|
wallets_set = set()
|
15955
16033
|
users_set = set()
|
15956
|
-
pay_set = set()
|
15957
16034
|
|
15958
16035
|
def process_user_rows(rows):
|
15959
|
-
# months = ["2025-06", "2025-07", "2025-08", "2025-09"]
|
15960
|
-
# data_users = []
|
15961
|
-
# for _ in range(3):
|
15962
|
-
# # дата входа
|
15963
|
-
# entry_month = random.choice(months)
|
15964
|
-
# entry_day = random.randint(1, 28)
|
15965
|
-
# entry_date = f"{entry_month}-{entry_day:02}"
|
15966
|
-
# entry_dt_obj = datetime.strptime(entry_date, '%Y-%m-%d')
|
15967
|
-
# entry_dt = f"{entry_dt_obj.strftime('%d-%m-%Y')}_{datetime.now().strftime('%H-%M-%S')}"
|
15968
|
-
# utm = random.choice(["/start", "/startapp"])
|
15969
|
-
#
|
15970
|
-
# # месяцы от входа и дальше
|
15971
|
-
# valid_months = [m for m in months if datetime.strptime(m + "-01", "%Y-%m-%d") >= entry_dt_obj.replace(day=1)]
|
15972
|
-
# if not valid_months:
|
15973
|
-
# valid_months = [entry_month]
|
15974
|
-
#
|
15975
|
-
# user_mau = sorted(random.sample(valid_months, k=random.randint(1, len(valid_months))))
|
15976
|
-
# user_dau_dates = set()
|
15977
|
-
# txs, payments = [], []
|
15978
|
-
#
|
15979
|
-
# # транзакция
|
15980
|
-
# if user_mau and random.random() < 0.5:
|
15981
|
-
# tx_month = random.choice(user_mau)
|
15982
|
-
# tx_day = random.randint(1, 28)
|
15983
|
-
# tx_date = f"{tx_month}-{tx_day:02}"
|
15984
|
-
# dt_tx = datetime.strptime(tx_date, "%Y-%m-%d")
|
15985
|
-
# if dt_tx >= entry_dt_obj:
|
15986
|
-
# txs = [{
|
15987
|
-
# "TYPE": random.choice(["don", "sub", "pst"]),
|
15988
|
-
# "AMOUNT": str(random.randint(1, 10)),
|
15989
|
-
# "ADDRESS": f"address{random.randint(1, 999)}",
|
15990
|
-
# "DT_START": f"{dt_tx.strftime('%d-%m-%Y')}_12-00-00",
|
15991
|
-
# }]
|
15992
|
-
# user_dau_dates.add(tx_date)
|
15993
|
-
#
|
15994
|
-
# # платеж
|
15995
|
-
# if user_mau and random.random() < 0.5:
|
15996
|
-
# pay_month = random.choice(user_mau)
|
15997
|
-
# pay_day = random.randint(1, 28)
|
15998
|
-
# pay_date = f"{pay_month}-{pay_day:02}"
|
15999
|
-
# dt_pay = datetime.strptime(pay_date, "%Y-%m-%d")
|
16000
|
-
# if dt_pay >= entry_dt_obj:
|
16001
|
-
# payments = [{
|
16002
|
-
# "TYPE": random.choice(["don", "sub", "pst"]),
|
16003
|
-
# "DT_START": f"{dt_pay.strftime('%d-%m-%Y')}_14-00-00",
|
16004
|
-
# "DT_END": "0",
|
16005
|
-
# "AMOUNT": str(random.randint(1, 10))
|
16006
|
-
# }]
|
16007
|
-
# user_dau_dates.add(pay_date)
|
16008
|
-
#
|
16009
|
-
# # вход в приложение
|
16010
|
-
# user_dau_dates.add(entry_date)
|
16011
|
-
#
|
16012
|
-
# # остальные посещения
|
16013
|
-
# for m in user_mau:
|
16014
|
-
# day = random.randint(1, 28)
|
16015
|
-
# visit = f"{m}-{day:02}"
|
16016
|
-
# dt_visit = datetime.strptime(visit, "%Y-%m-%d")
|
16017
|
-
# if dt_visit >= entry_dt_obj and random.random() < 0.7:
|
16018
|
-
# user_dau_dates.add(visit)
|
16019
|
-
#
|
16020
|
-
# user_dau = sorted(user_dau_dates)
|
16021
|
-
# wallet = f"wallet{random.randint(1, 100)}" if txs else random.choice([f"wallet{random.randint(1, 100)}", ""])
|
16022
|
-
#
|
16023
|
-
# data_users.append((
|
16024
|
-
# random.randint(100000, 999999),
|
16025
|
-
# json.dumps({"USER_WALLET": wallet, "USER_UTM": utm, "USER_DT": entry_dt}),
|
16026
|
-
# json.dumps({"USER_DAU": user_dau, "USER_MAU": user_mau, "USER_TXS": txs, "USER_PAYMENTS": payments})
|
16027
|
-
# ))
|
16028
|
-
|
16029
16036
|
for USER_TID, USER_VARS, USER_LSTS in rows:
|
16030
16037
|
USER_VARS = json.loads(USER_VARS or "{}")
|
16031
16038
|
USER_LSTS = json.loads(USER_LSTS or "{}")
|
@@ -16081,6 +16088,8 @@ async def return_activity_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16081
16088
|
key = "/startapp" if USER_UTM == "/startapp" else "/start"
|
16082
16089
|
metrics_by_month[month_key][key] += 1
|
16083
16090
|
|
16091
|
+
process_user_rows(data_users)
|
16092
|
+
|
16084
16093
|
for item in data_ents:
|
16085
16094
|
ENT_TID = item[0]
|
16086
16095
|
sql = f'SELECT USER_TID, USER_VARS, USER_LSTS FROM {schema_name}_{ENT_TID}.USER'
|
@@ -16088,11 +16097,6 @@ async def return_activity_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16088
16097
|
print(f"schema_name {data_users=}")
|
16089
16098
|
process_user_rows(data_users)
|
16090
16099
|
|
16091
|
-
sql = f"SELECT USER_TID, USER_VARS, USER_LSTS FROM \"USER\""
|
16092
|
-
data_users = await db_select_pg(sql, (), BASE_P)
|
16093
|
-
print(f"{data_users=}")
|
16094
|
-
process_user_rows(data_users)
|
16095
|
-
|
16096
16100
|
all_months = sorted(metrics_by_month.keys())
|
16097
16101
|
f_name = os.path.join(EXTRA_D, "1_activity_metrics.csv")
|
16098
16102
|
with open(f_name, mode="w", encoding="utf-8", newline="") as csvfile:
|
@@ -16122,11 +16126,8 @@ async def return_activity_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16122
16126
|
await asyncio.sleep(round(random.uniform(0, 1), 2))
|
16123
16127
|
|
16124
16128
|
|
16125
|
-
async def return_unit_metrics(bot,
|
16129
|
+
async def return_unit_metrics(bot, data_users, EXTRA_D):
|
16126
16130
|
try:
|
16127
|
-
sql = 'SELECT USER_TID, USER_VARS, USER_LSTS FROM "USER"'
|
16128
|
-
data_users = await db_select_pg(sql, (), BASE_P)
|
16129
|
-
|
16130
16131
|
metrics = defaultdict(lambda: {
|
16131
16132
|
"new_users": 0,
|
16132
16133
|
"sum_amount": 0.0,
|
@@ -16165,13 +16166,14 @@ async def return_unit_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16165
16166
|
all_months = sorted(metrics.keys())
|
16166
16167
|
cumulative_users = 0
|
16167
16168
|
results = []
|
16168
|
-
|
16169
|
+
first_mrr = None
|
16170
|
+
|
16169
16171
|
for idx, mo in enumerate(all_months):
|
16170
16172
|
data = metrics[mo]
|
16171
16173
|
new_u = data["new_users"]
|
16172
16174
|
cumulative_users += new_u
|
16173
|
-
|
16174
16175
|
MRR = data["sum_amount"]
|
16176
|
+
|
16175
16177
|
def fmt(x):
|
16176
16178
|
return f"{x:.2f}".rstrip("0").rstrip(".") if x is not None else ""
|
16177
16179
|
|
@@ -16233,75 +16235,8 @@ async def return_unit_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16233
16235
|
await asyncio.sleep(round(random.uniform(0, 1), 2))
|
16234
16236
|
|
16235
16237
|
|
16236
|
-
async def return_cohort_metrics(bot,
|
16238
|
+
async def return_cohort_metrics(bot, data_users, EXTRA_D):
|
16237
16239
|
try:
|
16238
|
-
sql = 'SELECT USER_TID, USER_VARS, USER_LSTS FROM "USER"'
|
16239
|
-
data_users = await db_select_pg(sql, (), BASE_P)
|
16240
|
-
|
16241
|
-
months = ["2025-06", "2025-07", "2025-08", "2025-09"]
|
16242
|
-
data_users = []
|
16243
|
-
for _ in range(30):
|
16244
|
-
# дата входа
|
16245
|
-
entry_month = random.choice(months)
|
16246
|
-
entry_day = random.randint(1, 28)
|
16247
|
-
entry_date = f"{entry_month}-{entry_day:02}"
|
16248
|
-
entry_dt_obj = datetime.strptime(entry_date, '%Y-%m-%d')
|
16249
|
-
entry_dt = f"{entry_dt_obj.strftime('%d-%m-%Y')}_{datetime.now().strftime('%H-%M-%S')}"
|
16250
|
-
utm = random.choice(["/start", "/startapp"])
|
16251
|
-
|
16252
|
-
# месяцы от входа и дальше
|
16253
|
-
valid_months = [m for m in months if datetime.strptime(m + "-01", "%Y-%m-%d") >= entry_dt_obj.replace(day=1)]
|
16254
|
-
if not valid_months:
|
16255
|
-
valid_months = [entry_month]
|
16256
|
-
|
16257
|
-
user_mau = sorted(random.sample(valid_months, k=random.randint(1, len(valid_months))))
|
16258
|
-
user_dau_dates = set()
|
16259
|
-
txs, payments = [], []
|
16260
|
-
|
16261
|
-
# платеж
|
16262
|
-
if user_mau:
|
16263
|
-
pay_month = random.choice(user_mau)
|
16264
|
-
pay_day = random.randint(1, 28)
|
16265
|
-
pay_date = f"{pay_month}-{pay_day:02}"
|
16266
|
-
dt_pay = datetime.strptime(pay_date, "%Y-%m-%d")
|
16267
|
-
# if dt_pay >= entry_dt_obj:
|
16268
|
-
payments = [{
|
16269
|
-
"TYPE": random.choice(["don", "sub", "pst"]),
|
16270
|
-
"DT_START": f"{dt_pay.strftime('%d-%m-%Y')}_14-00-00",
|
16271
|
-
"DT_END": "0",
|
16272
|
-
"AMOUNT": str(random.randint(1, 10))
|
16273
|
-
}]
|
16274
|
-
user_dau_dates.add(pay_date)
|
16275
|
-
|
16276
|
-
# вход в приложение
|
16277
|
-
user_dau_dates.add(entry_date)
|
16278
|
-
for m in user_mau:
|
16279
|
-
day = random.randint(1, 28)
|
16280
|
-
visit = f"{m}-{day:02}"
|
16281
|
-
dt_visit = datetime.strptime(visit, "%Y-%m-%d")
|
16282
|
-
if dt_visit >= entry_dt_obj and random.random() < 0.7:
|
16283
|
-
user_dau_dates.add(visit)
|
16284
|
-
|
16285
|
-
# статусы (отток) с низкой вероятностью
|
16286
|
-
USER_STATUSES = []
|
16287
|
-
if random.random() < 0.2: # 10% шанс оттока
|
16288
|
-
churn_month = random.choice(valid_months)
|
16289
|
-
churn_day = random.randint(1, 28)
|
16290
|
-
churn_date = f"{churn_month}-{churn_day:02}"
|
16291
|
-
churn_ts = datetime.strptime(churn_date, "%Y-%m-%d").strftime("%d-%m-%Y") + "_23-59-59"
|
16292
|
-
USER_STATUSES = [{random.choice(["left", "kicked"]): churn_ts}]
|
16293
|
-
|
16294
|
-
user_dau = sorted(user_dau_dates)
|
16295
|
-
wallet = f"wallet{random.randint(1, 100)}" if txs else random.choice([f"wallet{random.randint(1, 100)}", ""])
|
16296
|
-
|
16297
|
-
data_users.append((
|
16298
|
-
random.randint(100000, 999999),
|
16299
|
-
json.dumps({"USER_WALLET": wallet, "USER_UTM": utm, "USER_DT": entry_dt}),
|
16300
|
-
json.dumps({"USER_DAU": user_dau, "USER_MAU": user_mau, "USER_TXS": txs,
|
16301
|
-
"USER_PAYMENTS": payments, "USER_STATUSES": USER_STATUSES})
|
16302
|
-
))
|
16303
|
-
print(f"gen {data_users=}")
|
16304
|
-
|
16305
16240
|
cohorts = defaultdict(set)
|
16306
16241
|
activity_months = defaultdict(set)
|
16307
16242
|
|
@@ -16324,13 +16259,6 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16324
16259
|
cohort_months = sorted(cohorts.keys())
|
16325
16260
|
num_months = len(cohort_months)
|
16326
16261
|
|
16327
|
-
def add_months(mo_str, n):
|
16328
|
-
y, m = map(int, mo_str.split("-"))
|
16329
|
-
total = m + n
|
16330
|
-
new_y = y + (total - 1) // 12
|
16331
|
-
new_m = (total - 1) % 12 + 1
|
16332
|
-
return f"{new_y:04d}-{new_m:02d}"
|
16333
|
-
|
16334
16262
|
# Собираем таблицу посменно по календарным месяцам
|
16335
16263
|
table = []
|
16336
16264
|
header = ["Месяц/Когорта"]
|
@@ -16398,75 +16326,8 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16398
16326
|
await asyncio.sleep(round(random.uniform(0, 1), 2))
|
16399
16327
|
|
16400
16328
|
|
16401
|
-
async def return_retention_metrics(bot,
|
16329
|
+
async def return_retention_metrics(bot, data_users, EXTRA_D):
|
16402
16330
|
try:
|
16403
|
-
sql = 'SELECT USER_TID, USER_VARS, USER_LSTS FROM "USER"'
|
16404
|
-
data_users = await db_select_pg(sql, (), BASE_P)
|
16405
|
-
|
16406
|
-
months = ["2025-06", "2025-07", "2025-08", "2025-09"]
|
16407
|
-
data_users = []
|
16408
|
-
for _ in range(30):
|
16409
|
-
# дата входа
|
16410
|
-
entry_month = random.choice(months)
|
16411
|
-
entry_day = random.randint(1, 28)
|
16412
|
-
entry_date = f"{entry_month}-{entry_day:02}"
|
16413
|
-
entry_dt_obj = datetime.strptime(entry_date, '%Y-%m-%d')
|
16414
|
-
entry_dt = f"{entry_dt_obj.strftime('%d-%m-%Y')}_{datetime.now().strftime('%H-%M-%S')}"
|
16415
|
-
utm = random.choice(["/start", "/startapp"])
|
16416
|
-
|
16417
|
-
# месяцы от входа и дальше
|
16418
|
-
valid_months = [m for m in months if datetime.strptime(m + "-01", "%Y-%m-%d") >= entry_dt_obj.replace(day=1)]
|
16419
|
-
if not valid_months:
|
16420
|
-
valid_months = [entry_month]
|
16421
|
-
|
16422
|
-
user_mau = sorted(random.sample(valid_months, k=random.randint(1, len(valid_months))))
|
16423
|
-
user_dau_dates = set()
|
16424
|
-
txs, payments = [], []
|
16425
|
-
|
16426
|
-
# платеж
|
16427
|
-
if user_mau:
|
16428
|
-
pay_month = random.choice(user_mau)
|
16429
|
-
pay_day = random.randint(1, 28)
|
16430
|
-
pay_date = f"{pay_month}-{pay_day:02}"
|
16431
|
-
dt_pay = datetime.strptime(pay_date, "%Y-%m-%d")
|
16432
|
-
# if dt_pay >= entry_dt_obj:
|
16433
|
-
payments = [{
|
16434
|
-
"TYPE": random.choice(["don", "sub", "pst"]),
|
16435
|
-
"DT_START": f"{dt_pay.strftime('%d-%m-%Y')}_14-00-00",
|
16436
|
-
"DT_END": "0",
|
16437
|
-
"AMOUNT": str(random.randint(1, 10))
|
16438
|
-
}]
|
16439
|
-
user_dau_dates.add(pay_date)
|
16440
|
-
|
16441
|
-
# вход в приложение
|
16442
|
-
user_dau_dates.add(entry_date)
|
16443
|
-
for m in user_mau:
|
16444
|
-
day = random.randint(1, 28)
|
16445
|
-
visit = f"{m}-{day:02}"
|
16446
|
-
dt_visit = datetime.strptime(visit, "%Y-%m-%d")
|
16447
|
-
if dt_visit >= entry_dt_obj and random.random() < 0.7:
|
16448
|
-
user_dau_dates.add(visit)
|
16449
|
-
|
16450
|
-
# статусы (отток) с низкой вероятностью
|
16451
|
-
USER_STATUSES = []
|
16452
|
-
if random.random() < 0.2: # 10% шанс оттока
|
16453
|
-
churn_month = random.choice(valid_months)
|
16454
|
-
churn_day = random.randint(1, 28)
|
16455
|
-
churn_date = f"{churn_month}-{churn_day:02}"
|
16456
|
-
churn_ts = datetime.strptime(churn_date, "%Y-%m-%d").strftime("%d-%m-%Y") + "_23-59-59"
|
16457
|
-
USER_STATUSES = [{random.choice(["left", "kicked"]): churn_ts}]
|
16458
|
-
|
16459
|
-
user_dau = sorted(user_dau_dates)
|
16460
|
-
wallet = f"wallet{random.randint(1, 100)}" if txs else random.choice([f"wallet{random.randint(1, 100)}", ""])
|
16461
|
-
|
16462
|
-
data_users.append((
|
16463
|
-
random.randint(100000, 999999),
|
16464
|
-
json.dumps({"USER_WALLET": wallet, "USER_UTM": utm, "USER_DT": entry_dt}),
|
16465
|
-
json.dumps({"USER_DAU": user_dau, "USER_MAU": user_mau, "USER_TXS": txs,
|
16466
|
-
"USER_PAYMENTS": payments, "USER_STATUSES": USER_STATUSES})
|
16467
|
-
))
|
16468
|
-
print(f"gen {data_users=}")
|
16469
|
-
|
16470
16331
|
rev_by_cohort = defaultdict(lambda: defaultdict(float))
|
16471
16332
|
cohort_users = defaultdict(set)
|
16472
16333
|
|
@@ -16553,75 +16414,8 @@ async def return_retention_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16553
16414
|
await asyncio.sleep(round(random.uniform(0, 1), 2))
|
16554
16415
|
|
16555
16416
|
|
16556
|
-
async def return_profit_and_loss_metrics(bot,
|
16417
|
+
async def return_profit_and_loss_metrics(bot, data_users, EXTRA_D):
|
16557
16418
|
try:
|
16558
|
-
sql = 'SELECT USER_TID, USER_VARS, USER_LSTS FROM "USER"'
|
16559
|
-
data_users = await db_select_pg(sql, (), BASE_P)
|
16560
|
-
|
16561
|
-
months = ["2025-06", "2025-07", "2025-08", "2025-09"]
|
16562
|
-
data_users = []
|
16563
|
-
for _ in range(30):
|
16564
|
-
# дата входа
|
16565
|
-
entry_month = random.choice(months)
|
16566
|
-
entry_day = random.randint(1, 28)
|
16567
|
-
entry_date = f"{entry_month}-{entry_day:02}"
|
16568
|
-
entry_dt_obj = datetime.strptime(entry_date, '%Y-%m-%d')
|
16569
|
-
entry_dt = f"{entry_dt_obj.strftime('%d-%m-%Y')}_{datetime.now().strftime('%H-%M-%S')}"
|
16570
|
-
utm = random.choice(["/start", "/startapp"])
|
16571
|
-
|
16572
|
-
# месяцы от входа и дальше
|
16573
|
-
valid_months = [m for m in months if datetime.strptime(m + "-01", "%Y-%m-%d") >= entry_dt_obj.replace(day=1)]
|
16574
|
-
if not valid_months:
|
16575
|
-
valid_months = [entry_month]
|
16576
|
-
|
16577
|
-
user_mau = sorted(random.sample(valid_months, k=random.randint(1, len(valid_months))))
|
16578
|
-
user_dau_dates = set()
|
16579
|
-
txs, payments = [], []
|
16580
|
-
|
16581
|
-
# платеж
|
16582
|
-
if user_mau:
|
16583
|
-
pay_month = random.choice(user_mau)
|
16584
|
-
pay_day = random.randint(1, 28)
|
16585
|
-
pay_date = f"{pay_month}-{pay_day:02}"
|
16586
|
-
dt_pay = datetime.strptime(pay_date, "%Y-%m-%d")
|
16587
|
-
# if dt_pay >= entry_dt_obj:
|
16588
|
-
payments = [{
|
16589
|
-
"TYPE": random.choice(["don", "sub", "pst"]),
|
16590
|
-
"DT_START": f"{dt_pay.strftime('%d-%m-%Y')}_14-00-00",
|
16591
|
-
"DT_END": "0",
|
16592
|
-
"AMOUNT": str(random.randint(10, 1000))
|
16593
|
-
}]
|
16594
|
-
user_dau_dates.add(pay_date)
|
16595
|
-
|
16596
|
-
# вход в приложение
|
16597
|
-
user_dau_dates.add(entry_date)
|
16598
|
-
for m in user_mau:
|
16599
|
-
day = random.randint(1, 28)
|
16600
|
-
visit = f"{m}-{day:02}"
|
16601
|
-
dt_visit = datetime.strptime(visit, "%Y-%m-%d")
|
16602
|
-
if dt_visit >= entry_dt_obj and random.random() < 0.7:
|
16603
|
-
user_dau_dates.add(visit)
|
16604
|
-
|
16605
|
-
# статусы (отток) с низкой вероятностью
|
16606
|
-
USER_STATUSES = []
|
16607
|
-
if random.random() < 0.2: # 10% шанс оттока
|
16608
|
-
churn_month = random.choice(valid_months)
|
16609
|
-
churn_day = random.randint(1, 28)
|
16610
|
-
churn_date = f"{churn_month}-{churn_day:02}"
|
16611
|
-
churn_ts = datetime.strptime(churn_date, "%Y-%m-%d").strftime("%d-%m-%Y") + "_23-59-59"
|
16612
|
-
USER_STATUSES = [{random.choice(["left", "kicked"]): churn_ts}]
|
16613
|
-
|
16614
|
-
user_dau = sorted(user_dau_dates)
|
16615
|
-
wallet = f"wallet{random.randint(1, 100)}" if txs else random.choice([f"wallet{random.randint(1, 100)}", ""])
|
16616
|
-
|
16617
|
-
data_users.append((
|
16618
|
-
random.randint(100000, 999999),
|
16619
|
-
json.dumps({"USER_WALLET": wallet, "USER_UTM": utm, "USER_DT": entry_dt}),
|
16620
|
-
json.dumps({"USER_DAU": user_dau, "USER_MAU": user_mau, "USER_TXS": txs,
|
16621
|
-
"USER_PAYMENTS": payments, "USER_STATUSES": USER_STATUSES})
|
16622
|
-
))
|
16623
|
-
print(f"gen {data_users=}")
|
16624
|
-
|
16625
16419
|
metrics = defaultdict(lambda: {"sum_amount": 0.0})
|
16626
16420
|
|
16627
16421
|
for USER_TID, USER_VARS, USER_LSTS in data_users:
|
@@ -16642,18 +16436,18 @@ async def return_profit_and_loss_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P)
|
|
16642
16436
|
results = []
|
16643
16437
|
|
16644
16438
|
for mo in months_sorted:
|
16645
|
-
# Преобразуем "2025-06" → "JUN"
|
16646
|
-
dt_mo = datetime.strptime(mo, "%Y-%m")
|
16647
|
-
mon_str = dt_mo.strftime("%b").upper()
|
16648
|
-
|
16649
16439
|
MRR = metrics[mo]["sum_amount"]
|
16650
16440
|
COGS = 0.0
|
16651
16441
|
GP = MRR - COGS
|
16652
16442
|
OPEX = 4.5
|
16653
16443
|
OP = GP - OPEX
|
16654
|
-
|
16655
|
-
|
16656
|
-
|
16444
|
+
|
16445
|
+
# из OP сначала вычитаем 30%, затем из результата вычитаем 1%
|
16446
|
+
after_comm = OP * 0.70 # остаётся после 30% комиссии
|
16447
|
+
after_fiat = after_comm * 0.99 # остаётся после ещё 1% на обмен
|
16448
|
+
COMM = OP - after_comm # сама комиссия (30% от OP)
|
16449
|
+
EXCH = after_comm - after_fiat # сама часть обмена (1% от остатка после комиссии)
|
16450
|
+
NP = after_fiat # чистая прибыль
|
16657
16451
|
|
16658
16452
|
results.append([
|
16659
16453
|
mo,
|
@@ -16682,7 +16476,6 @@ async def return_profit_and_loss_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P)
|
|
16682
16476
|
except Exception as e:
|
16683
16477
|
logger.info(log_ % str(e))
|
16684
16478
|
await asyncio.sleep(round(random.uniform(0, 1), 2))
|
16685
|
-
|
16686
16479
|
# endregion
|
16687
16480
|
|
16688
16481
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|