The EDAC Object allows us access to powerful functions like EDACSetItem, which sets values in any EDGAR file when you pass the name of a data point and its value. You can use this to create EDGAR files from stored data files of any type or from databases, which is a very powerful automation tool.
I’ve written a small sample script that shows how the EDACSetItem function can be used. This script is going to pass data from specified in the script to build an N-PORT filing.
handle edac;
int rc;
int main(){
rc = RunMenuFunction("FILE_NEW_SUBMISSION", "Form:NPORT-P");
edac = EDACOpenView();
// Filer Information Fields
rc = EDACSetItem(edac,"name","Steven");
if (IsError(rc)){
AddMessage("Error: 1 %0xd",rc);
}
rc = EDACSetItem(edac,"phone","585-424-1700");
if (IsError(rc)){
AddMessage("Error: 2 %0xd",rc);
}
rc = EDACSetItem(edac,"email","support@novaworkssoftware.com");
if (IsError(rc)){
AddMessage("Error: 3 %0xd",rc);
}
rc = EDACSetItem(edac,"cik","7246172");
if (IsError(rc)){
AddMessage("Error: 4 %0xd",rc);
}
rc = EDACSetItem(edac,"ccc","test@123");
if (IsError(rc)){
AddMessage("Error: 5 %0xd",rc);
}
rc = EDACSetItem(edac,"overrideInternetFlag","Y");
if (IsError(rc)){
AddMessage("Error: 6 %0xd",rc);
}
rc = EDACSetItem(edac,"invstCompanyType","Bad!");
if (IsError(rc)){
AddMessage("Error: 7 %0xd",rc);
}
// Table Fields
rc = EDACSetItem(edac,"invstOrSecs[000]:name","Default Name");
if (IsError(rc)){
AddMessage("Error: 8 %0xd",rc);
}
rc = EDACSetItem(edac,"invstOrSecs[000]:cusip","C1234569");
if (IsError(rc)){
AddMessage("Error: 9 %0xd",rc);
}
rc = EDACSetItem(edac,"invstOrSecs[000]:identifiers[000]:isin","123456789");
if (IsError(rc)){
AddMessage("Error: 10 %0xd",rc);
}
rc = EDACSetItem(edac,"invstOrSecs[000]:identifiers[001]:isin","123456789");
if (IsError(rc)){
AddMessage("Error: 11 %0xd",rc);
}
rc = EDACSetItem(edac,"invstOrSecs[000]:assetCat","debt");
if (IsError(rc)){
AddMessage("Error: 11 %0xd",rc);
}
rc = EDACSetItem(edac,"invstOrSecs[000]:assetConditional:desc","test");
if (IsError(rc)){
AddMessage("Error: 11 %0xd",rc);
}
CloseHandle(edac);
return ERROR_NONE;
}
The first function called is RunMenuFunction to create a new submission with the NPORT-P EDGAR form type. Once that file is open, we can use EDACGetView to grab the EDAC module for the currently open view. The main function used for interacting with the document is EDACSetItem, mentioned earlier, which we can use to set values.
In my sample script, I’m setting fields to fixed values, but it’s certainly possible to create more advanced UI elements that prompt users for input for fields or to open data files to read values. GoFiler can interface with Office documents (like Excel files) using OLE Automation functions and can connect to databases with ODBC functions. Either of those functions can interface with the EDAC Object to pass the data for the EDGAR form fields. With EDAC, we have the final piece required to fully automate creation of documents, pulling information from a variety of sources and consolidating them together.
Now, when you run the sample script above, don’t be alarmed. The script returns an “Error: 7 84000000d”. This is a syntax error that will happen because the script sets the value for the field “invstCompanyType” to “bad”. The N-PORT Technical specification only allows known investment company types, such as N-1, for this field. It’s important to check the return codes when using EDAC. If EDAC fails to set a value, it’s most likely because the value is invalid or too large for the field. If we tried to set a CUSIP value that was 40 characters long, for example, we’d also get a syntax error, because it exceeds the maximum allowable length of the CUSIP field.
Try setting the “invstCompanyType” to “N-1” and running the script again.
The example also shows how to handle multi entry lists, in the lines of code below:
rc = EDACSetItem(edac,"invstOrSecs[000]:name","Default Name");
if (IsError(rc)){
AddMessage("Error: 8 %0xd",rc);
}
rc = EDACSetItem(edac,"invstOrSecs[000]:cusip","C1234569");
if (IsError(rc)){
AddMessage("Error: 9 %0xd",rc);
}
rc = EDACSetItem(edac,"invstOrSecs[000]:identifiers[000]:isin","123456789");
if (IsError(rc)){
AddMessage("Error: 10 %0xd",rc);
}
rc = EDACSetItem(edac,"invstOrSecs[000]:identifiers[001]:isin","123456789");
if (IsError(rc)){
AddMessage("Error: 11 %0xd",rc);
}
rc = EDACSetItem(edac,"invstOrSecs[000]:assetCat","debt");
if (IsError(rc)){
AddMessage("Error: 11 %0xd",rc);
}
rc = EDACSetItem(edac,"invstOrSecs[000]:assetConditional:desc","test");
if (IsError(rc)){
AddMessage("Error: 11 %0xd",rc);
}
If a field allows multiple entries, we can handle it as though it was an array by using a zero-based index. The first line in this example is setting the name value in the invstOrSecs list. The name of the field we pass EDAC then is “invstOrSecs[000]:name”, so we know it’s the first item in a zero-based array. If the array allows further sub lists, they can be accessed in a similar way. The third EDACSetItem call in this example is setting the ISIN value in the identifiers list, which is a sub-list of the invstOrSecs list. The call to set the first element of this list would require the name to be “invstOrSecs[000]:identifiers[000]:isin”. We can use “invstOrSecs[000]:identifiers[001]:isin” to set the second one, and so on. These variables all need to be accounted for by the programmer implementing an EDAC interface, but it’s fairly straightforward if you’re using for loops to just count what index the list and sublists are on.
Care also needs to be taken on what elements are being set. Normally in GoFiler, fields are greyed out if they are not applicable to the form being filled out. With EDAC, you can still access and edit these values, since it does not take the context of the element into consideration when the EDAC function sets it. In the example above, I’m setting the value for assetConditional:desc to “test”, even though the field is greyed out in GoFiler. This isn’t really a problem in this case, because when the file is saved, greyed out fields are not written out to the file, so if the file is saved, closed, and re-opened the information is not retained. It is something that a programmer using this class should be aware of though.
Another important thing to remember with EDAC is that the EDAC object must be closed after you’re finished with it. Using the CloseHandle function is all you really have to do here to release the handle, so the form can be accessed by GoFiler normally. This isn’t a problem if we’re using the EDAC class like in the example above, since the handles are automatically released when the script ends. However, if we’re using the EDAC class as a global variable in our script, and the script is running as a menu hooked function, the script doesn’t clear those global variables until the application closes, meaning we won’t be able to actually use our form unless we close the handle. It’s best to just get into the habit of manually closing the handle so we won’t have to worry about it.
Having gotten the gist of how the EDACSetItem function works, the next question you might ask, is where do I get the names for the EDGAR form fields? How do you know that the GoFiler name for the Fair Value Level of Item C is “invstOrSecs[000]:fairValLevel”, and how do you know that the set of allowable values is 1, 2, 3, or N/A?
Well, for each form in GoFiler, there is an XDS data file that represents the data structure that GoFiler uses as a template for each form. N-PORT, for example, has a folder in GoFiler’s installation directory, with the file “form n-port.xds” in it. If you are running GoFiler with Beta Features Enabled (more on how to do that later), you can open this file and retrieve the form field information.
IMPORTANT: You should not edit any Form template XDS file. This will affect the performance of GoFiler and could potentially affect your ability to create a valid EDGAR submission for that form type.
To access the form template, click the (?) menu icon in the upper right corner of GoFiler. Then, while holding the Shift key, choose the About menu item. Instead of the normal About box, the Beta Features option dialog will appear. Enable the beta features. You must restart GoFiler for the beta features to function.
Once the beta features are enabled, just open the XDS file normally. It will appear in a Data Sheet edit window. Click on a data field and press the F12 key or click the Properties button on the Spreadsheet Ribbon. On the Attributes tab, look at the name field. That’s the EDAC field name. This will often match the SEC’s published XML technical specifications. If a field can only have certain values for it, you can look at the SEC’s technical specification or follow the options available in the drop-down list in GoFiler.
This is obviously just a silly little example of EDAC, but I hope the utility of the class is obvious here. I’ve used it to write custom imports for forms to speed up the data entry process, so a filing agent can simply send someone an Excel Template for the form, and the agent can then just run the script and all the data from the template immediately imports into an EDGAR compliant form. Like I said earlier, it can go even further, and can pull data from databases to compile information from multiple sources into an EDGAR file. Using EDAC, full automation of the file creation process is now possible and can drastically speed up operations when properly implemented.