117 lines
5.4 KiB
Python
117 lines
5.4 KiB
Python
from .cn_analyzer import CN_Analyzer
|
|
import pandas as pd
|
|
|
|
class VN_Analyzer(CN_Analyzer):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.market = 'VN'
|
|
|
|
self.mapping = {
|
|
'income': {
|
|
'revenue': 'revenue',
|
|
'net_income': 'net_income',
|
|
'gross_profit': 'gross_profit',
|
|
'total_profit': 'total_profit',
|
|
'sga_exp': 'sga_exp'
|
|
},
|
|
'balance': {
|
|
'total_equity': 'total_equity',
|
|
'total_assets': 'total_assets',
|
|
'total_liabilities': 'total_liabilities',
|
|
'current_assets': 'current_assets',
|
|
'current_liabilities': 'current_liabilities',
|
|
'cash': 'cash',
|
|
'receivables': 'receivables',
|
|
'inventory': 'inventory',
|
|
'fixed_assets': 'fixed_assets',
|
|
'goodwill': 'goodwill',
|
|
'short_term_debt': 'short_term_debt',
|
|
'long_term_debt': 'long_term_debt'
|
|
},
|
|
'cashflow': {
|
|
'ocf': 'ocf',
|
|
'capex': 'capex',
|
|
'dividends': 'dividends'
|
|
}
|
|
}
|
|
|
|
def _post_process_columns(self, df, type):
|
|
if market_type := self.mapping.get(type):
|
|
for col in market_type.values():
|
|
if col in df.columns:
|
|
df[col] = pd.to_numeric(df[col], errors='coerce')
|
|
|
|
df = super()._post_process_columns(df, type)
|
|
if type == 'balance':
|
|
if 'long_term_investments' in df.columns:
|
|
df['lt_invest'] = df['long_term_investments']
|
|
|
|
if 'long_term_debt' not in df.columns: df['long_term_debt'] = 0
|
|
if 'long_term_borrowings' in df.columns:
|
|
df['long_term_debt'] = df['long_term_debt'].fillna(0) + df['long_term_borrowings'].fillna(0)
|
|
return df
|
|
|
|
def calculate_indicators(self, df_merged, market_metrics, historical_metrics):
|
|
if 'revenue' in df_merged.columns and 'gross_profit' in df_merged.columns:
|
|
df_merged['cogs'] = df_merged['revenue'] - df_merged['gross_profit']
|
|
|
|
df_merged = super().calculate_indicators(df_merged, market_metrics, historical_metrics)
|
|
|
|
has_sga = False
|
|
if 'sga_exp' in df_merged.columns and 'revenue' in df_merged.columns:
|
|
if df_merged['sga_exp'].notna().any() and (df_merged['sga_exp'] != 0).any():
|
|
df_merged['SgaRatio'] = self._safe_div(df_merged['sga_exp'], df_merged['revenue'])
|
|
has_sga = True
|
|
|
|
if not has_sga:
|
|
sga_sum = 0
|
|
if 'selling_exp' in df_merged.columns: sga_sum = sga_sum + df_merged['selling_exp'].fillna(0)
|
|
if 'admin_exp' in df_merged.columns: sga_sum = sga_sum + df_merged['admin_exp'].fillna(0)
|
|
if 'revenue' in df_merged.columns:
|
|
df_merged['SgaRatio'] = self._safe_div(sga_sum, df_merged['revenue'])
|
|
|
|
if 'income_tax' in df_merged.columns and 'net_income' in df_merged.columns:
|
|
ebt_approx = df_merged['net_income'] + df_merged['income_tax']
|
|
df_merged['TaxRate'] = self._safe_div(df_merged['income_tax'], ebt_approx)
|
|
|
|
if 'GrossMargin' in df_merged.columns and 'NetMargin' in df_merged.columns:
|
|
other_ratio = df_merged['GrossMargin'] - df_merged['NetMargin']
|
|
if 'SgaRatio' in df_merged.columns:
|
|
other_ratio = other_ratio - df_merged['SgaRatio'].fillna(0)
|
|
if 'RDRatio' in df_merged.columns:
|
|
other_ratio = other_ratio - df_merged['RDRatio'].fillna(0)
|
|
df_merged['OtherExpenseRatio'] = other_ratio
|
|
|
|
if 'MarketCap' in df_merged.columns:
|
|
if 'net_income' in df_merged.columns:
|
|
calculated_pe = self._safe_div(df_merged['MarketCap'], df_merged['net_income'])
|
|
if 'PE' not in df_merged.columns:
|
|
df_merged['PE'] = calculated_pe
|
|
else:
|
|
cond_pe = (df_merged['PE'] != 0) & df_merged['PE'].notna()
|
|
df_merged['PE'] = df_merged['PE'].where(cond_pe, calculated_pe)
|
|
|
|
if 'total_equity' in df_merged.columns:
|
|
calculated_pb = self._safe_div(df_merged['MarketCap'], df_merged['total_equity'])
|
|
if 'PB' not in df_merged.columns:
|
|
df_merged['PB'] = calculated_pb
|
|
else:
|
|
cond_pb = (df_merged['PB'] != 0) & df_merged['PB'].notna()
|
|
df_merged['PB'] = df_merged['PB'].where(cond_pb, calculated_pb)
|
|
|
|
if 'dividends' in df_merged.columns:
|
|
calculated_yield = self._safe_div(df_merged['dividends'], df_merged['MarketCap']) * 100
|
|
if 'DividendYield' not in df_merged.columns:
|
|
df_merged['DividendYield'] = calculated_yield
|
|
else:
|
|
df_merged['DividendYield'] = df_merged['DividendYield'].fillna(calculated_yield)
|
|
|
|
if 'employee_count' in df_merged.columns:
|
|
df_merged['Employees'] = df_merged['employee_count']
|
|
if 'revenue' in df_merged.columns:
|
|
df_merged['RevenuePerEmp'] = self._safe_div(df_merged['revenue'], df_merged['employee_count'])
|
|
if 'net_income' in df_merged.columns:
|
|
df_merged['ProfitPerEmp'] = self._safe_div(df_merged['net_income'], df_merged['employee_count'])
|
|
|
|
return df_merged
|