見出し画像

ファンダメンタルズ指標

既存のインジケータまとめて使ってるよシリーズ第2弾
企業の業績や財務状況を中心とする基礎的な株価の指標をまとめたものです

※ 財務と業績についてはまた今度追加します

任意の新しいインジケータを作成します
既存のインジケータの一株益、株価収益率、株主資本利益率、一株当たり株主資本、株価純資産倍率をまとめて1つにして表示しているだけです

既存の物と見比べてインジケータの幅はほとんど変わりませんが、
レーダースクリーンに表示出来るインジケータ数はMAX30なので
既存の一株益、株価収益率、株主資本利益率、一株当たり株主資本、
株価純資産倍率、と5つ使うより少なく
使用個数に余裕ができ、連結/単独の入力も1回で済みます

必要のない項目は見出し部分を右クリックしてプロットを表示/非表示で!

プログラム

using tsdata.marketdata;
using elsystem;
using elsystem.collections;
inputs:
	int MonthsReported( 12 ) [DisplayName = "MonthsReported", ToolTip = 
	 "Enter the number of months in the reporting period for which data is desired.  Fundamental data usually covers a 3, 6 or 12 month period."],
	int ConsolidationLevel( 1 ) [DisplayName = "ConsolidationLevel", ToolTip = 
	 "Enter 1 if consolidated data is desired; enter any other value for non-consolidated data."],
	int AccountingStandard( 0 ) [DisplayName = "AccountingStandard", ToolTip = 
	 "Enter 1 for Japanese accounting standard; enter 2 for Securities and Exchange Commission (SEC) accounting standard; enter 3 for International Financial Reporting Standards (IFRS) accounting standard; enter 0 to use IFRS, SEC, or Japanese accounting standards, in that order, depending on which is available."],
	int PeriodsOfContinuousGrowthAlert( 4 ) [DisplayName = "PeriodsOfContinuousGrowthAlert", ToolTip = 
	 "Enter the number of reporting periods over which earnings must have continuously increased in order to trigger an alert."];
variables:
	FundamentalQuotesProvider FQP( NULL ),
	Dictionary DataDict( NULL ),
	intrabarpersist bool OkayToPlot( false ),
	intrabarpersist bool OkayToPlotActual( false ),
	intrabarpersist bool OkayToPlotForecast( false ),
	intrabarpersist string ConsLevel( "Consolidated" ),
	intrabarpersist string AcctStdInputString( "" ),
	bool Continuous( false ),
	int PeriodsAgoCounter( 0 ),
	double CREPS( 0 ),
	double CREPS2( 0 ),
	double CEEPS( 0 ),
	double CREPS3( 0 ),
	double CRPER( 0 ),
	double CEPER( 0 ),
	double CRROE( 0 ),
	double CCRROARBPS( 0 ),
	double CRBPS( 0 ),
	double CRPBR( 0 ),
	double CEPBR( 0 );
constants:
	string MonthsReportedKey( "MonthsReported" ),
	string ConsolidatedKey( "ConsolidationLevel" ),
	string AccountingKey( "AccountingStandard" ),
	string EPSActualFieldName( "CR_EPS" ),
	string EPSForecastFieldName( "CE_EPS" ),
	string PERActualFieldName( "CR_PER" ),
	string PERForecastFieldName( "CE_PER" ),
	string ROEFieldName( "CR_ROE" ),
	string ROAFieldName( "CR_ROA" ),
	string BookValuePerShareFieldName( "CR_BPS" ),
	string PBRActualFieldName( "CR_PBR" ),
	string PBRForecastFieldName( "CE_PBR" ),
	string ConsolidatedValue( "Consolidated" ),
	string NonConsolidatedValue( "NonConsolidated" ),
	string ValuesAdder( "_Values" ),
	string IFRSString( "IFRS" ),
	string SECString( "SEC" ),
	string JSTDString( "JSTD" );
	
method void CreateFundamentalQuotesProvider()
begin
	FQP = new FundamentalQuotesProvider();
	FQP.Symbol = Symbol;
	FQP.Fields += EPSActualFieldName;
	FQP.Fields += EPSForecastFieldName;
	FQP.Fields += PERActualFieldName;
	FQP.Fields += PERForecastFieldName;
	FQP.Fields += ROEFieldName;
	FQP.Fields += ROAFieldName;
	FQP.Fields += BookValuePerShareFieldName;
	FQP.Fields += PBRActualFieldName;
	FQP.Fields += PBRForecastFieldName;
	FQP.Realtime = false;
	FQP.TimeZone = tsdata.common.TimeZone.local;
	FQP.LoadProvider();
	Value99 = FQP.Count; { force provider to load }
end;
method bool DataHasPostDate( FundamentalQuote fq )
variables:  int Counter, DateTime MissingDT, int NumMissingDates;
begin
	NumMissingDates = 0;
	MissingDT = DateTime.Create( 1999, 11, 30 );
	for Counter = 0 to fq.Count - 1 begin
		if fq.PostDate[Counter] = MissingDT then
			NumMissingDates += 1;
	end;
	return NumMissingDates <> fq.Count;
end;
method string GetAcctStdString()
variables:  string AcctStdString;
begin
	switch ( AccountingStandard ) begin
		case 1: { JSTD }
			AcctStdString = JSTDString;
		case 2: { SEC }
			AcctStdString = SECString;
		case 3: { IFRS }
			AcctStdString = IFRSString;
	end;
	return AcctStdString;
end;
method bool GetQuoteAsOfDate( FundamentalQuote fq, DateTime tempdt, 
out double QuoteVal )
variables:  
	int Counter,
	bool QuoteFound, 
	DateTime LastDateTime,  
	string AcctStd, 
	string LastUsedAcctStd, 
	bool SetVariable,
	DateTime fqDateTime;
begin
	if fq = NULL or tempdt = NULL then return false;
	QuoteFound = false;
	LastDateTime = DateTime.Create( 1900, 1, 1 );
	SetVariable = false;
	for Counter = fq.Count - 1 downto 0 begin
		SetVariable = false;
		AcctStd = fq.ExtendedProperties[Counter][AccountingKey].StringValue;
		if fq.ExtendedProperties[Counter][MonthsReportedKey].IntegerValue = MonthsReported
			and fq.ExtendedProperties[Counter][ConsolidatedKey].StringValue	= ConsLevel
			and ( AccountingStandard = 0 or AcctStd = AcctStdInputString ) then begin
			fqDateTime = fq.PostDate[Counter];
			if tempdt >= fqDateTime and fqDateTime >= LastDateTime then begin
				if fqDateTime <> LastDateTime then begin { new PostDate }
					SetVariable = true;
				end else if AccountingStandard = 0 then begin { use hierarchy }
					if AcctStd = IFRSString then begin
						SetVariable = true;
					end else if AcctStd = SECString and LastUsedAcctStd <> IFRSString then begin
						SetVariable = true;
					end else if AcctStd = JSTDString 
						and LastUsedAcctStd <> IFRSString 
						and LastUsedAcctStd <> SECString then begin
						SetVariable = true;
					end;				
				end;	
			end;		
		end;	
		if SetVariable then begin
			QuoteVal = fq.DoubleValue[Counter];
			LastUsedAcctStd = AcctStd;
			LastDateTime = fqDateTime;
			QuoteFound = true;
		end;
	end;
	return QuoteFound;
end;{ GetQuoteAsOfDate method }
method bool GetQuoteAsOfDate2( string FieldName, DateTime tempdt, int PeriodsAgo, 
out double QuoteVal )
variables:  
	int Counter,
	bool QuoteFound,
	bool SetVariable,
	DateTime VectDateTime,
	Vector QuoteDateTimeVector,
	Vector QuoteValuesVector;
begin
	if FieldName = "" or tempdt = NULL or DataDict = NULL or PeriodsAgo < 0 then return false;
	QuoteDateTimeVector = DataDict[FieldName] astype Vector;
	QuoteValuesVector = DataDict[FieldName + ValuesAdder] astype Vector;
	QuoteFound = false;
	SetVariable = false;
	for Counter = QuoteDateTimeVector.Count - 1 downto 0 begin
		SetVariable = false;
		VectDateTime = QuoteDateTimeVector[Counter] astype DateTime;
		if tempdt >= VectDateTime then begin { quote date is before date passed in }
			SetVariable = true;
		end else begin
			break;
		end;
		
		if SetVariable then begin
			if Counter + PeriodsAgo <= QuoteDateTimeVector.Count - 1 then begin			
				QuoteVal = QuoteValuesVector[Counter + PeriodsAgo] astype double;
				QuoteFound = true;
			end;
		end;
	end;
	return QuoteFound;
end;{ GetQuoteAsOfDate2 method }
method void LoadFundDataVectors( string ifundField )
variables:  
	int Counter, 
	Vector dateVect, 
	Vector valuesVect,
	FundamentalQuote fq,
	string fqAcctStd,
	string LastAcctStd,
	bool LoadThisQuote,
	bool ReplaceLastValue,
	bool NumMonthsOkay,
	bool ConsLevelOkay,
	DateTime LastDateTime;
begin
	if DataDict = NULL then
		DataDict = new Dictionary();
		dateVect = new Vector();
		valuesVect = new Vector();
		DataDict.Add( ifundField, dateVect astype Vector );
		DataDict.Add( ifundField + ValuesAdder, valuesVect astype Vector );
		fq = FQP[ifundField];
		LastDateTime = DateTime.Create( 1900, 1, 1 );	
	for Counter = 0 to fq.Count - 1 begin
		LoadThisQuote = false;
		ReplaceLastValue = false;
		fqAcctStd = fq.ExtendedProperties[Counter][AccountingKey].StringValue;
		NumMonthsOkay = fq.ExtendedProperties[Counter][MonthsReportedKey].IntegerValue = MonthsReported;
		ConsLevelOkay = fq.ExtendedProperties[Counter][ConsolidatedKey].StringValue = ConsLevel;
		if NumMonthsOkay 
			and ConsLevelOkay
			and ( AccountingStandard = 0 or fqAcctStd = AcctStdInputString ) then begin
			if fq.PostDate[Counter] <> LastDateTime then begin { new date }
				LoadThisQuote = true;
			end else begin
				switch ( fqAcctStd ) begin
					case IFRSString:
						ReplaceLastValue = true;
					case SECString:
						if LastAcctStd <> IFRSString then
							ReplaceLastValue = true;
					case JSTDString:
						if LastAcctStd <> IFRSString and LastAcctStd <> SECString then
							ReplaceLastValue = true;
				end;
			end;
		end;	
		if LoadThisQuote then begin
			dateVect.push_back( fq.PostDate[Counter] astype DateTime );
			valuesVect.push_back( fq.DoubleValue[Counter] astype double );
			LastAcctStd = fqAcctStd;
			LastDateTime = fq.PostDate[Counter];
		end else if ReplaceLastValue then begin
			valuesVect[Counter-1] = fq.DoubleValue[Counter] astype double;
			LastAcctStd = fqAcctStd;
		end;
	end;
end;{ LoadFundDataVectors method }
once begin
	if ConsolidationLevel = 1 then ConsLevel = ConsolidatedValue
	else ConsLevel = NonConsolidatedValue;
	AcctStdInputString = GetAcctStdString();
	CreateFundamentalQuotesProvider();
	
	if FQP.HasQuoteData( EPSActualFieldName ) then begin
		OkayToPlotActual = true;
		LoadFundDataVectors( EPSActualFieldName );
	end;
	
	if FQP.HasQuoteData( EPSForecastFieldName ) then begin
		OkayToPlotForecast = true;
		LoadFundDataVectors( EPSForecastFieldName );
	end;
	
	OkayToPlotActual = FQP.HasQuoteData( PERActualFieldName )
	 and DataHasPostDate( FQP[PERActualFieldName] );
	
	OkayToPlotForecast = FQP.HasQuoteData( PERForecastFieldName )
	 and DataHasPostDate( FQP[PERForecastFieldName] );
	OkayToPlot = FQP.HasQuoteData( ROEFieldName )
	 and DataHasPostDate( FQP[ROEFieldName] );
	OkayToPlot = FQP.HasQuoteData( ROAFieldName )
	 and DataHasPostDate( FQP[ROAFieldName] );
	 
	OkayToPlot = FQP.HasQuoteData( BookValuePerShareFieldName )
	 and DataHasPostDate( FQP[BookValuePerShareFieldName] );
	OkayToPlotActual = FQP.HasQuoteData( PBRActualFieldName )
	 and DataHasPostDate( FQP[PBRActualFieldName] );
	
	OkayToPlotForecast = FQP.HasQuoteData( PBRForecastFieldName )
	 and DataHasPostDate( FQP[PBRForecastFieldName] );
end;
if OkayToPlotActual and GetQuoteAsOfDate2( EPSActualFieldName, BarDateTime, 0, CREPS ) then
	Plot1( CREPS, !( "実EPS" ) );											//実績1株当たり利益
if OkayToPlotForecast and GetQuoteAsOfDate2( EPSForecastFieldName, BarDateTime, 0, CEEPS ) then
	Plot2( CEEPS, !( "予EPS" ) );											//予想1株当たり利益
	
if OkayToPlotActual and GetQuoteAsOfDate( FQP[PERActualFieldName], BarDateTime, CRPER ) then
	Plot3( CRPER, !( "実PER" ) );											//実績株価収益率
if OkayToPlotForecast and GetQuoteAsOfDate( FQP[PERForecastFieldName], BarDateTime, CEPER ) then
	Plot4( CEPER, !( "予PER" ) );											//予想株価収益率
if OkayToPlot and GetQuoteAsOfDate( FQP[ROEFieldName], BarDateTime, CRROE ) then
	Plot5( CRROE, !( "ROE" ) );												//株主資本利益率
if OkayToPlot and GetQuoteAsOfDate( FQP[ROAFieldName], BarDateTime, CCRROARBPS ) then
	Plot6( CCRROARBPS, !( "ROA" ) );										//総資産利益率
	
if OkayToPlot and GetQuoteAsOfDate( FQP[BookValuePerShareFieldName], BarDateTime, CRBPS ) then
	Plot7( CRBPS, !( "BPS" ) );												//1株当たり純資産
if OkayToPlotActual and GetQuoteAsOfDate( FQP[PBRActualFieldName], BarDateTime, CRPBR ) then
	Plot8( CRPBR, !( "実PBR" ) );											//実績株価純資産倍率
if OkayToPlotForecast and GetQuoteAsOfDate( FQP[PBRForecastFieldName], BarDateTime, CEPBR ) then
	Plot9( CEPBR, !( "予PBR" ) );											//予想株価純資産倍率
	
{ alert criteria }
if AlertEnabled then begin
	Continuous = true;
	for PeriodsAgoCounter = 0 to PeriodsOfContinuousGrowthAlert - 1 begin
		if GetQuoteAsOfDate2( EPSActualFieldName, BarDateTime, 
		 	 PeriodsAgoCounter, CREPS2 ) = false
			or GetQuoteAsOfDate2( EPSActualFieldName, BarDateTime, 
			 PeriodsAgoCounter + 1, CREPS3 ) = false
			or CREPS2 <= CREPS3 then begin
			Continuous = false;
			break;
		end;
	end;
	
	if Continuous then begin
		Alert( !( "The number of quarters of continuous EPS growth is >= " ) +
		 NumToStr( PeriodsOfContinuousGrowthAlert, 0 ) );
	end;
end;

サポートされると喜んでアイスを買っちゃいます!٩(๑❛ᴗ❛๑)۶